From 3d2054aa0afce7e20c848794867e7b562bdb9424 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 4 Apr 2019 10:14:02 +1100 Subject: [PATCH 001/366] WorldEdit accepts a pattern for these commands update the message to reflect that. --- .../sk89q/worldedit/command/RegionCommands.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 1e5fb3fee..d788063d5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -85,7 +85,7 @@ public class RegionCommands { @Command( aliases = { "/line" }, - usage = " [thickness]", + usage = " [thickness]", desc = "Draws a line segment between cuboid selection corners", help = "Draws a line segment between cuboid selection corners.\n" + @@ -119,7 +119,7 @@ public class RegionCommands { @Command( aliases = { "/curve" }, - usage = " [thickness]", + usage = " [thickness]", desc = "Draws a spline through selected points", help = "Draws a spline through selected points.\n" + @@ -170,7 +170,7 @@ public class RegionCommands { @Command( aliases = { "/overlay" }, - usage = "", + usage = "", desc = "Set a block on top of blocks in the region", min = 1, max = 1 @@ -184,7 +184,7 @@ public class RegionCommands { @Command( aliases = { "/center", "/middle" }, - usage = "", + usage = "", desc = "Set the center block(s)", min = 1, max = 1 @@ -212,7 +212,7 @@ public class RegionCommands { @Command( aliases = { "/walls" }, - usage = "", + usage = "", desc = "Build the four sides of the selection", min = 1, max = 1 @@ -226,7 +226,7 @@ public class RegionCommands { @Command( aliases = { "/faces", "/outline" }, - usage = "", + usage = "", desc = "Build the walls, ceiling, and floor of a selection", min = 1, max = 1 @@ -414,7 +414,7 @@ public class RegionCommands { @Command( aliases = { "/hollow" }, - usage = "[[ ]]", + usage = "[[ ]]", desc = "Hollows out the object contained in this selection", help = "Hollows out the object contained in this selection.\n" + From 9ba11215921bbdd9121c506f279aadb034a93313 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 4 Apr 2019 10:45:21 +1100 Subject: [PATCH 002/366] swap order of checks since a boolean check is faster than getting inventory item + string comparison --- .../extension/platform/PlatformManager.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index 1f124dd23..3b8347e7d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -321,11 +321,7 @@ public class PlatformManager { try { if (event.getType() == Interaction.HIT) { - if (player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) { - if (!session.isToolControlEnabled()) { - return; - } - + if (session.isToolControlEnabled() && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) { if (!actor.hasPermission("worldedit.selection.pos")) { return; } @@ -341,7 +337,7 @@ public class PlatformManager { return; } - if (player.isHoldingPickAxe() && session.hasSuperPickAxe()) { + if (session.hasSuperPickAxe() && player.isHoldingPickAxe()) { final BlockTool superPickaxe = session.getSuperPickaxe(); if (superPickaxe != null && superPickaxe.canUse(player)) { event.setCancelled(superPickaxe.actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location)); @@ -358,11 +354,7 @@ public class PlatformManager { } } else if (event.getType() == Interaction.OPEN) { - if (player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) { - if (!session.isToolControlEnabled()) { - return; - } - + if (session.isToolControlEnabled() && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) { if (!actor.hasPermission("worldedit.selection.pos")) { return; } From 4de5487c510971d9d9a2740a354a58b23d24b69a Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 4 Apr 2019 23:36:19 +1100 Subject: [PATCH 003/366] Change Vector hash codes (#456) And add additional unit vectors where needed. --- .../java/com/sk89q/worldedit/EditSession.java | 2 +- .../worldedit/command/SelectionCommands.java | 12 +++++------ .../function/visitor/BreadthFirstSearch.java | 21 ++++++++++--------- .../function/visitor/DownwardVisitor.java | 10 ++++----- .../function/visitor/NonRisingVisitor.java | 10 ++++----- .../sk89q/worldedit/math/BlockVector2.java | 5 +---- .../sk89q/worldedit/math/BlockVector3.java | 9 ++++---- .../worldedit/math/interpolation/Node.java | 2 +- .../com/sk89q/worldedit/util/Direction.java | 4 +++- 9 files changed, 37 insertions(+), 38 deletions(-) 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 07d3d084c..bf26a0a1f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -1182,7 +1182,7 @@ public class EditSession implements Extent, AutoCloseable { checkNotNull(pattern); BlockReplace replace = new BlockReplace(this, pattern); - RegionOffset offset = new RegionOffset(BlockVector3.at(0, 1, 0), replace); + RegionOffset offset = new RegionOffset(BlockVector3.UNIT_Y, replace); GroundFunction ground = new GroundFunction(new ExistingBlockMask(this), offset); LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground); Operations.completeLegacy(visitor); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 9ded39f33..24e92070b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -568,15 +568,15 @@ public class SelectionCommands { int change = args.getInteger(0); if (!args.hasFlag('h')) { - changes.add((BlockVector3.at(0, 1, 0)).multiply(change)); - changes.add((BlockVector3.at(0, -1, 0)).multiply(change)); + changes.add((BlockVector3.UNIT_Y).multiply(change)); + changes.add((BlockVector3.UNIT_MINUS_Y).multiply(change)); } if (!args.hasFlag('v')) { - changes.add((BlockVector3.at(1, 0, 0)).multiply(change)); - changes.add((BlockVector3.at(-1, 0, 0)).multiply(change)); - changes.add((BlockVector3.at(0, 0, 1)).multiply(change)); - changes.add((BlockVector3.at(0, 0, -1)).multiply(change)); + changes.add((BlockVector3.UNIT_X).multiply(change)); + changes.add((BlockVector3.UNIT_MINUS_X).multiply(change)); + changes.add((BlockVector3.UNIT_Z).multiply(change)); + changes.add((BlockVector3.UNIT_MINUS_Z).multiply(change)); } return changes.toArray(new BlockVector3[0]); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java index f7260491e..26b14f38c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.RunContext; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; import java.util.ArrayDeque; import java.util.ArrayList; @@ -85,22 +86,22 @@ public abstract class BreadthFirstSearch implements Operation { * Add the directions along the axes as directions to visit. */ protected void addAxes() { - directions.add(BlockVector3.at(0, -1, 0)); - directions.add(BlockVector3.at(0, 1, 0)); - directions.add(BlockVector3.at(-1, 0, 0)); - directions.add(BlockVector3.at(1, 0, 0)); - directions.add(BlockVector3.at(0, 0, -1)); - directions.add(BlockVector3.at(0, 0, 1)); + directions.add(BlockVector3.UNIT_MINUS_Y); + directions.add(BlockVector3.UNIT_Y); + directions.add(BlockVector3.UNIT_MINUS_X); + directions.add(BlockVector3.UNIT_X); + directions.add(BlockVector3.UNIT_MINUS_Z); + directions.add(BlockVector3.UNIT_Z); } /** * Add the diagonal directions as directions to visit. */ protected void addDiagonal() { - directions.add(BlockVector3.at(1, 0, 1)); - directions.add(BlockVector3.at(-1, 0, -1)); - directions.add(BlockVector3.at(1, 0, -1)); - directions.add(BlockVector3.at(-1, 0, 1)); + directions.add(Direction.NORTHEAST.toBlockVector()); + directions.add(Direction.SOUTHEAST.toBlockVector()); + directions.add(Direction.SOUTHWEST.toBlockVector()); + directions.add(Direction.NORTHWEST.toBlockVector()); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java index 6c1740ce5..518eab096 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java @@ -53,11 +53,11 @@ public class DownwardVisitor extends RecursiveVisitor { Collection directions = getDirections(); directions.clear(); - directions.add(BlockVector3.at(1, 0, 0)); - directions.add(BlockVector3.at(-1, 0, 0)); - directions.add(BlockVector3.at(0, 0, 1)); - directions.add(BlockVector3.at(0, 0, -1)); - directions.add(BlockVector3.at(0, -1, 0)); + directions.add(BlockVector3.UNIT_X); + directions.add(BlockVector3.UNIT_MINUS_X); + directions.add(BlockVector3.UNIT_Z); + directions.add(BlockVector3.UNIT_MINUS_Z); + directions.add(BlockVector3.UNIT_MINUS_Y); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java index fd25108c9..752e00a1d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java @@ -40,11 +40,11 @@ public class NonRisingVisitor extends RecursiveVisitor { super(mask, function); Collection directions = getDirections(); directions.clear(); - directions.add(BlockVector3.at(1, 0, 0)); - directions.add(BlockVector3.at(-1, 0, 0)); - directions.add(BlockVector3.at(0, 0, 1)); - directions.add(BlockVector3.at(0, 0, -1)); - directions.add(BlockVector3.at(0, -1, 0)); + directions.add(BlockVector3.UNIT_X); + directions.add(BlockVector3.UNIT_MINUS_X); + directions.add(BlockVector3.UNIT_Z); + directions.add(BlockVector3.UNIT_MINUS_Z); + directions.add(BlockVector3.UNIT_MINUS_Y); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java index 5924899e5..92548fc99 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java @@ -525,10 +525,7 @@ public final class BlockVector2 { @Override public int hashCode() { - int hash = 17; - hash = 31 * hash + Integer.hashCode(x); - hash = 31 * hash + Integer.hashCode(z); - return hash; + return (x << 16) ^ z; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index db545c716..ffb6f6347 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -35,6 +35,9 @@ public final class BlockVector3 { public static final BlockVector3 UNIT_X = new BlockVector3(1, 0, 0); public static final BlockVector3 UNIT_Y = new BlockVector3(0, 1, 0); public static final BlockVector3 UNIT_Z = new BlockVector3(0, 0, 1); + public static final BlockVector3 UNIT_MINUS_X = new BlockVector3(-1, 0, 0); + public static final BlockVector3 UNIT_MINUS_Y = new BlockVector3(0, -1, 0); + public static final BlockVector3 UNIT_MINUS_Z = new BlockVector3(0, 0, -1); public static final BlockVector3 ONE = new BlockVector3(1, 1, 1); public static BlockVector3 at(double x, double y, double z) { @@ -609,11 +612,7 @@ public final class BlockVector3 { @Override public int hashCode() { - int hash = 17; - hash = 31 * hash + Integer.hashCode(x); - hash = 31 * hash + Integer.hashCode(y); - hash = 31 * hash + Integer.hashCode(z); - return hash; + return (x ^ (z << 12)) ^ (y << 24); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/interpolation/Node.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/interpolation/Node.java index c29190b77..3a020653e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/interpolation/Node.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/interpolation/Node.java @@ -38,7 +38,7 @@ public class Node { private double continuity; public Node() { - this(Vector3.at(0, 0, 0)); + this(Vector3.ZERO); } public Node(Node other) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/Direction.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/Direction.java index dea0528d0..d40df5935 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/Direction.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/Direction.java @@ -58,8 +58,10 @@ public enum Direction { private final Vector3 direction; private final int flags; + private final BlockVector3 blockPoint; Direction(Vector3 vector, int flags) { + this.blockPoint = vector.toBlockPoint(); this.direction = vector.normalize(); this.flags = flags; } @@ -121,7 +123,7 @@ public enum Direction { * @return the vector */ public BlockVector3 toBlockVector() { - return direction.toBlockPoint(); + return blockPoint; } /** From 1966e5a8a24f0f14927fe5cd3a2eadfd58df7fee Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 14 Mar 2019 02:10:37 -0700 Subject: [PATCH 004/366] Initial Piston conversion test. Non-functional. --- gradle/wrapper/gradle-wrapper.properties | 3 +- settings.gradle | 4 +- worldedit-core/build.gradle | 73 +++++++++-------- .../worldedit/command/SchematicCommands.java | 80 +++++++++---------- .../command/util/AsyncCommandHelper.java | 7 +- .../util/paste/ActorCallbackPaste.java | 3 +- 6 files changed, 91 insertions(+), 79 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a95009c3b..a9534e761 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Thu Mar 14 00:19:48 PDT 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip diff --git a/settings.gradle b/settings.gradle index 576283ecc..6b725d8d1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,5 @@ rootProject.name = 'worldedit' -include 'worldedit-core', 'worldedit-bukkit', 'worldedit-forge', 'worldedit-sponge' \ No newline at end of file +include 'worldedit-core', 'worldedit-bukkit', 'worldedit-forge', 'worldedit-sponge' + +includeBuild("../Piston") diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index f91186083..3047ad577 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -1,32 +1,41 @@ -apply plugin: 'eclipse' -apply plugin: 'idea' - -dependencies { - compile 'de.schlichtherle:truezip:6.8.3' - compile 'rhino:js:1.7R2' - compile 'org.yaml:snakeyaml:1.9' - compile 'com.google.guava:guava:21.0' - compile 'com.sk89q:jchronic:0.2.4a' - compile 'com.google.code.findbugs:jsr305:1.3.9' - compile 'com.thoughtworks.paranamer:paranamer:2.6' - compile 'com.google.code.gson:gson:2.8.0' - compile 'com.sk89q.lib:jlibnoise:1.0.0' - compile 'com.googlecode.json-simple:json-simple:1.1.1' - compile 'org.slf4j:slf4j-api:1.7.26' - //compile 'net.sf.trove4j:trove4j:3.0.3' - testCompile 'org.mockito:mockito-core:1.9.0-rc1' -} - -sourceSets { - main { - java { - srcDir 'src/main/java' - srcDir 'src/legacy/java' - } - resources { - srcDir 'src/main/resources' - } - } -} - -build.dependsOn(shadowJar) +plugins { + id("net.ltgt.apt") version "0.21" +} + +apply plugin: 'eclipse' +apply plugin: 'idea' +apply plugin: 'net.ltgt.apt-eclipse' +apply plugin: 'net.ltgt.apt-idea' + +dependencies { + compile 'de.schlichtherle:truezip:6.8.3' + compile 'rhino:js:1.7R2' + compile 'org.yaml:snakeyaml:1.9' + compile 'com.google.guava:guava:21.0' + compile 'com.sk89q:jchronic:0.2.4a' + compile 'com.google.code.findbugs:jsr305:1.3.9' + compile 'com.thoughtworks.paranamer:paranamer:2.6' + compile 'com.google.code.gson:gson:2.8.0' + compile 'com.sk89q.lib:jlibnoise:1.0.0' + compile 'com.googlecode.json-simple:json-simple:1.1.1' + compile 'org.slf4j:slf4j-api:1.7.26' + compileOnly 'org.enginehub.piston:core-ap-annotations:0.0.1-SNAPSHOT' + annotationProcessor 'org.enginehub.piston:core-ap-processor:0.0.1-SNAPSHOT' + compile 'org.enginehub.piston:default-impl:0.0.1-SNAPSHOT' + //compile 'net.sf.trove4j:trove4j:3.0.3' + testCompile 'org.mockito:mockito-core:1.9.0-rc1' +} + +sourceSets { + main { + java { + srcDir 'src/main/java' + srcDir 'src/legacy/java' + } + resources { + srcDir 'src/main/resources' + } + } +} + +build.dependsOn(shadowJar) 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 ab8ff950b..d685318f8 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 @@ -21,7 +21,6 @@ package com.sk89q.worldedit.command; import com.google.common.collect.Multimap; import com.google.common.io.Files; -import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; @@ -41,10 +40,13 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.session.ClipboardHolder; -import com.sk89q.worldedit.util.command.binding.Switch; -import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.io.file.FilenameException; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,6 +66,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Commands that work with schematic files. */ +@CommandContainer public class SchematicCommands { /** @@ -84,13 +87,13 @@ public class SchematicCommands { } @Command( - aliases = { "load" }, - usage = "[] ", - desc = "Load a schematic into your clipboard", - min = 1, max = 2 + name = "load", + desc = "Load a schematic into your clipboard" ) - @CommandPermissions({ "worldedit.clipboard.load", "worldedit.schematic.load" }) - public void load(Player player, LocalSession session, @Optional("sponge") String formatName, String filename) throws FilenameException { + @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load"}) + public void load(Player player, LocalSession session, + @Arg(desc = "File name.") String filename, + @Arg(desc = "Format name.", def = "sponge") String formatName) throws FilenameException { LocalConfiguration config = worldEdit.getConfiguration(); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); @@ -127,16 +130,15 @@ public class SchematicCommands { } @Command( - aliases = { "save" }, - flags = "f", - usage = "[] ", - desc = "Save a schematic into your clipboard", - help = "-f is required to overwrite an existing file", - min = 1, max = 2 + name = "save", + desc = "Save a schematic into your clipboard" ) - @CommandPermissions({ "worldedit.clipboard.save", "worldedit.schematic.save" }) - public void save(Player player, LocalSession session, @Optional("sponge") String formatName, - String filename, @Switch('f') boolean allowOverwrite) throws CommandException, WorldEditException { + @CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save"}) + public void save(Player player, LocalSession session, + @Arg(desc = "File name.") String filename, + @Arg(desc = "Format name.", def = "sponge") String formatName, + @Switch(name = 'f', desc = "Overwrite an existing file.") boolean allowOverwrite + ) throws CommandException, WorldEditException { LocalConfiguration config = worldEdit.getConfiguration(); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); @@ -198,15 +200,13 @@ public class SchematicCommands { } @Command( - aliases = { "delete", "d" }, - usage = "", - desc = "Delete a saved schematic", - help = "Delete a schematic from the schematic list", - min = 1, - max = 1 + name = "delete", + aliases = {"d"}, + desc = "Delete a saved schematic" ) @CommandPermissions("worldedit.schematic.delete") - public void delete(Actor actor, String filename) throws WorldEditException { + public void delete(Actor actor, + @Arg(desc = "File name.") String filename) throws WorldEditException { LocalConfiguration config = worldEdit.getConfiguration(); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); @@ -232,12 +232,12 @@ public class SchematicCommands { } @Command( - aliases = {"formats", "listformats", "f"}, - desc = "List available formats", - max = 0 + name = "formats", + aliases = {"listformats", "f"}, + desc = "List available formats" ) @CommandPermissions("worldedit.schematic.formats") - public void formats(Actor actor) throws WorldEditException { + public void formats(Actor actor) { actor.print("Available clipboard formats (Name: Lookup names)"); StringBuilder builder; boolean first = true; @@ -257,18 +257,14 @@ public class SchematicCommands { } @Command( - aliases = {"list", "all", "ls"}, - desc = "List saved schematics", - max = 1, - flags = "dnp", - help = "List all schematics in the schematics directory\n" + - " -d sorts by date, oldest first\n" + - " -n sorts by date, newest first\n" + - " -p prints the requested page\n" + - "Note: Format is not thoroughly verified until loading." + name = "list", + aliases = {"all", "ls"}, + desc = "List saved schematics", + descFooter = "Note: Format is not fully verified until loading." ) @CommandPermissions("worldedit.schematic.list") - public void list(Actor actor, CommandContext args, @Switch('p') @Optional("1") int page) throws WorldEditException { + public void list(Actor actor, CommandContext args, + @ArgFlag(name = 'p', desc = "Page to view.", def = "1") int page) { File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir); List fileList = allFiles(dir); @@ -315,7 +311,7 @@ public class SchematicCommands { actor.print("Available schematics (Filename: Format) [" + page + "/" + pageCount + "]:"); StringBuilder build = new StringBuilder(); int limit = Math.min(offset + SCHEMATICS_PER_PAGE, schematics.size()); - for (int i = offset; i < limit;) { + for (int i = offset; i < limit; ) { build.append(schematics.get(i)); if (++i != limit) { build.append("\n"); @@ -351,10 +347,10 @@ public class SchematicCommands { //ClipboardFormat format = ClipboardFormats.findByFile(file); Multimap exts = ClipboardFormats.getFileExtensionMap(); ClipboardFormat format = exts.get(Files.getFileExtension(file.getName())) - .stream().findFirst().orElse(null); + .stream().findFirst().orElse(null); boolean inRoot = file.getParentFile().getName().equals(prefix); build.append(inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1]) - .append(": ").append(format == null ? "Unknown" : format.getName() + "*"); + .append(": ").append(format == null ? "Unknown" : format.getName() + "*"); result.add(build.toString()); } return result; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java index f3b707435..7557b0834 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java @@ -30,6 +30,7 @@ import com.sk89q.worldedit.util.task.Supervisor; import com.sk89q.worldedit.world.World; import javax.annotation.Nullable; +import java.util.concurrent.ForkJoinPool; public class AsyncCommandHelper { @@ -85,7 +86,8 @@ public class AsyncCommandHelper { .exceptionConverter(exceptionConverter) .onSuccess(format(success)) .onFailure(format(failure)) - .build()); + .build(), + ForkJoinPool.commonPool()); return this; } @@ -96,7 +98,8 @@ public class AsyncCommandHelper { new MessageFutureCallback.Builder(sender) .exceptionConverter(exceptionConverter) .onFailure(format(failure)) - .build()); + .build(), + ForkJoinPool.commonPool()); return this; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java index bcacbfd8f..4c86e6866 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java @@ -30,6 +30,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URL; +import java.util.concurrent.ForkJoinPool; public class ActorCallbackPaste { @@ -65,7 +66,7 @@ public class ActorCallbackPaste { LOGGER.warn("Failed to submit pastebin", throwable); sender.printError("Failed to submit to a pastebin. Please see console for the error."); } - }); + }, ForkJoinPool.commonPool()); } } From 8ab6585815474986c0b93f5144f5041861dfd92c Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 4 Apr 2019 16:16:04 -0700 Subject: [PATCH 005/366] Patch new cmds system into old system --- config/checkstyle/import-control.xml | 2 + worldedit-bukkit/build.gradle | 6 ++ worldedit-core/build.gradle | 9 +- .../worldedit/command/SchematicCommands.java | 22 +++-- .../command/util/CommandPermissions.java | 39 ++++++++ .../CommandPermissionsConditionGenerator.java | 49 ++++++++++ .../extension/platform/CommandManager.java | 32 +++++-- .../platform/CommandManagerCallable.java | 90 +++++++++++++++++++ worldedit-forge/build.gradle | 6 ++ 9 files changed, 238 insertions(+), 17 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissions.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 28ccad1e4..5bcfffeb3 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -16,6 +16,8 @@ + + diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 335b96c0a..3c5832e9b 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -8,6 +8,12 @@ repositories { maven { url 'https://papermc.io/repo/repository/maven-public/' } } +configurations.all { Configuration it -> + it.resolutionStrategy { ResolutionStrategy rs -> + rs.force("com.google.guava:guava:21.0") + } +} + dependencies { compile project(':worldedit-core') compile 'com.sk89q:dummypermscompat:1.10' diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index 3047ad577..5f6cce5a6 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -7,6 +7,12 @@ apply plugin: 'idea' apply plugin: 'net.ltgt.apt-eclipse' apply plugin: 'net.ltgt.apt-idea' +configurations.all { Configuration it -> + it.resolutionStrategy { ResolutionStrategy rs -> + rs.force("com.google.guava:guava:21.0") + } +} + dependencies { compile 'de.schlichtherle:truezip:6.8.3' compile 'rhino:js:1.7R2' @@ -20,7 +26,8 @@ dependencies { compile 'com.googlecode.json-simple:json-simple:1.1.1' compile 'org.slf4j:slf4j-api:1.7.26' compileOnly 'org.enginehub.piston:core-ap-annotations:0.0.1-SNAPSHOT' - annotationProcessor 'org.enginehub.piston:core-ap-processor:0.0.1-SNAPSHOT' + compile 'org.enginehub.piston:core-ap-runtime:0.0.1-SNAPSHOT' + annotationProcessor 'org.enginehub.piston:core-ap-processor:0.0.1-SNAPSHOT' compile 'org.enginehub.piston:default-impl:0.0.1-SNAPSHOT' //compile 'net.sf.trove4j:trove4j:3.0.3' testCompile 'org.mockito:mockito-core:1.9.0-rc1' 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 d685318f8..2bdd77bf0 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 @@ -21,13 +21,11 @@ package com.sk89q.worldedit.command; import com.google.common.collect.Multimap; import com.google.common.io.Files; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -49,6 +47,7 @@ import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.enginehub.piston.exception.StopExecutionException; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -138,7 +137,7 @@ public class SchematicCommands { @Arg(desc = "File name.") String filename, @Arg(desc = "Format name.", def = "sponge") String formatName, @Switch(name = 'f', desc = "Overwrite an existing file.") boolean allowOverwrite - ) throws CommandException, WorldEditException { + ) throws WorldEditException { LocalConfiguration config = worldEdit.getConfiguration(); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); @@ -154,7 +153,7 @@ public class SchematicCommands { boolean overwrite = f.exists(); if (overwrite) { if (!player.hasPermission("worldedit.schematic.delete")) { - throw new CommandException("That schematic already exists!"); + throw new StopExecutionException("That schematic already exists!"); } if (!allowOverwrite) { player.printError("That schematic already exists. Use the -f flag to overwrite it."); @@ -181,7 +180,7 @@ public class SchematicCommands { File parent = f.getParentFile(); if (parent != null && !parent.exists()) { if (!parent.mkdirs()) { - throw new CommandException("Could not create folder for schematics!"); + throw new StopExecutionException("Could not create folder for schematics!"); } } @@ -263,8 +262,13 @@ public class SchematicCommands { descFooter = "Note: Format is not fully verified until loading." ) @CommandPermissions("worldedit.schematic.list") - public void list(Actor actor, CommandContext args, - @ArgFlag(name = 'p', desc = "Page to view.", def = "1") int page) { + public void list(Actor actor, + @ArgFlag(name = 'p', desc = "Page to view.", def = "1") int page, + @Switch(name = 'd', desc = "Sort by date, oldest first") boolean oldFirst, + @Switch(name = 'n', desc = "Sort by date, newest first") boolean newFirst) { + if (oldFirst && newFirst) { + throw new StopExecutionException("Cannot sort by oldest and newest."); + } File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir); List fileList = allFiles(dir); @@ -286,7 +290,7 @@ public class SchematicCommands { return; } - final int sortType = args.hasFlag('d') ? -1 : args.hasFlag('n') ? 1 : 0; + final int sortType = oldFirst ? -1 : newFirst ? 1 : 0; // cleanup file list Arrays.sort(files, (f1, f2) -> { // http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissions.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissions.java new file mode 100644 index 000000000..feefb9aba --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissions.java @@ -0,0 +1,39 @@ +/* + * 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.command.util; + +import org.enginehub.piston.annotation.CommandCondition; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +@CommandCondition(CommandPermissionsConditionGenerator.class) +public @interface CommandPermissions { + + /** + * A list of permissions. Only one permission has to be met + * for the command to be permitted. + * + * @return a list of permissions strings + */ + String[] value(); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java new file mode 100644 index 000000000..d00d286d6 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java @@ -0,0 +1,49 @@ +/* + * 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.command.util; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Key; +import com.sk89q.worldedit.extension.platform.Actor; +import org.enginehub.piston.Command; +import org.enginehub.piston.gen.CommandConditionGenerator; +import org.enginehub.piston.util.NonnullByDefault; + +import java.lang.reflect.Method; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +@NonnullByDefault +public class CommandPermissionsConditionGenerator implements CommandConditionGenerator { + + private static final Key ACTOR_KEY = Key.get(Actor.class); + + @Override + public Command.Condition generateCondition(Method commandMethod) { + CommandPermissions annotation = commandMethod.getAnnotation(CommandPermissions.class); + checkNotNull(annotation, "Annotation is missing from commandMethod"); + Set permissions = ImmutableSet.copyOf(annotation.value()); + return p -> { + Actor actor = p.injectedValue(ACTOR_KEY); + return permissions.stream().anyMatch(actor::hasPermission); + }; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index a0be07b65..9a2a9da78 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -19,10 +19,8 @@ package com.sk89q.worldedit.extension.platform; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.util.command.composition.LegacyCommandAdapter.adapt; - import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.minecraft.util.commands.CommandPermissionsException; @@ -41,6 +39,7 @@ import com.sk89q.worldedit.command.HistoryCommands; import com.sk89q.worldedit.command.NavigationCommands; import com.sk89q.worldedit.command.RegionCommands; import com.sk89q.worldedit.command.SchematicCommands; +import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.ScriptingCommands; import com.sk89q.worldedit.command.SelectionCommands; import com.sk89q.worldedit.command.SnapshotCommands; @@ -57,6 +56,7 @@ import com.sk89q.worldedit.command.composition.DeformCommand; import com.sk89q.worldedit.command.composition.PaintCommand; import com.sk89q.worldedit.command.composition.SelectionCommand; import com.sk89q.worldedit.command.composition.ShapedBrushCommand; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; @@ -69,8 +69,10 @@ import com.sk89q.worldedit.internal.command.UserCommandCompleter; import com.sk89q.worldedit.internal.command.WorldEditBinding; import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.command.CommandCallable; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.InvalidUsageException; +import com.sk89q.worldedit.util.command.SimpleDescription; import com.sk89q.worldedit.util.command.composition.ProvidedValue; import com.sk89q.worldedit.util.command.fluent.CommandGraph; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; @@ -82,6 +84,7 @@ import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; import com.sk89q.worldedit.world.World; +import org.enginehub.piston.DefaultCommandManagerService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -91,6 +94,9 @@ import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.regex.Pattern; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.util.command.composition.LegacyCommandAdapter.adapt; + /** * Handles the registration and invocation of commands. * @@ -158,10 +164,7 @@ public final class CommandManager { .describeAs("WorldEdit commands") .registerMethods(new WorldEditCommands(worldEdit)) .parent() - .group("schematic", "schem", "/schematic", "/schem") - .describeAs("Schematic commands for saving/loading areas") - .registerMethods(new SchematicCommands(worldEdit)) - .parent() + .register(schematicCommands(),"schematic", "schem", "/schematic", "/schem") .group("snapshot", "snap") .describeAs("Schematic commands for saving/loading areas") .registerMethods(new SnapshotCommands(worldEdit)) @@ -189,6 +192,21 @@ public final class CommandManager { .getDispatcher(); } + private CommandCallable schematicCommands() { + SimpleDescription desc = new SimpleDescription(); + desc.setDescription("Schematic commands for saving/loading areas"); + desc.setPermissions(ImmutableList.of()); + org.enginehub.piston.CommandManager manager = DefaultCommandManagerService.getInstance() + .newCommandManager(); + new SchematicCommandsRegistration( + manager, + new SchematicCommands(worldEdit), + new CommandPermissionsConditionGenerator() + ); + + return new CommandManagerCallable(worldEdit, manager, desc); + } + public ExceptionConverter getExceptionConverter() { return exceptionConverter; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java new file mode 100644 index 000000000..bb6079713 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java @@ -0,0 +1,90 @@ +/* + * 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.extension.platform; + +import com.google.common.base.Splitter; +import com.google.inject.Key; +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.minecraft.util.commands.CommandLocals; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.util.command.CommandCallable; +import com.sk89q.worldedit.util.command.Description; +import org.enginehub.piston.CommandManager; + +import java.util.Collections; +import java.util.List; + +/** + * Hack to get {@link CommandManager} working under {@link CommandCallable}. + */ +public class CommandManagerCallable implements CommandCallable { + + private final WorldEdit worldEdit; + private final CommandManager manager; + private final Description description; + + public CommandManagerCallable(WorldEdit worldEdit, CommandManager manager, Description description) { + this.worldEdit = worldEdit; + this.manager = manager; + this.description = description; + } + + @Override + public Object call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException { + manager.injectValue(Key.get(Actor.class), () -> locals.get(Actor.class)); + manager.injectValue(Key.get(Player.class), () -> getPlayer(locals)); + manager.injectValue(Key.get(LocalSession.class), () -> { + Player sender = getPlayer(locals); + return worldEdit.getSessionManager().get(sender); + }); + manager.injectValue(Key.get(EditSession.class), () -> { + Player sender = getPlayer(locals); + LocalSession session = worldEdit.getSessionManager().get(sender); + EditSession editSession = session.createEditSession(sender); + editSession.enableStandardMode(); + session.tellVersion(sender); + return editSession; + }); + return manager.execute(Splitter.on(' ').splitToList(arguments)); + } + + private Player getPlayer(CommandLocals locals) { + Actor actor = locals.get(Actor.class); + return actor instanceof Player ? (Player) actor : null; + } + + @Override + public Description getDescription() { + return description; + } + + @Override + public boolean testPermission(CommandLocals locals) { + return true; + } + + @Override + public List getSuggestions(String arguments, CommandLocals locals) throws CommandException { + return Collections.emptyList(); + } +} diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 8fe3fb9af..62b38c8e8 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -16,6 +16,12 @@ apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13.2" def forgeVersion = "25.0.76" +configurations.all { Configuration it -> + it.resolutionStrategy { ResolutionStrategy rs -> + rs.force("com.google.guava:guava:21.0") + } +} + dependencies { compile project(':worldedit-core') compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.2' From fa8139f4b3327c078344419293e0159d91626f3e Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 5 Apr 2019 14:46:29 -0400 Subject: [PATCH 006/366] Transfer Request to evaluation thread for Expressions. --- .../worldedit/internal/expression/Expression.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java index 944fd97d8..0e82a4750 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.internal.expression.runtime.Functions; import com.sk89q.worldedit.internal.expression.runtime.RValue; import com.sk89q.worldedit.internal.expression.runtime.ReturnException; import com.sk89q.worldedit.internal.expression.runtime.Variable; +import com.sk89q.worldedit.session.request.Request; import java.util.HashMap; import java.util.List; @@ -142,7 +143,18 @@ public class Expression { } private double evaluateRootTimed(int timeout) throws EvaluationException { - Future result = evalThread.submit(this::evaluateRoot); + Request request = Request.request(); + Future result = evalThread.submit(() -> { + Request local = Request.request(); + local.setSession(request.getSession()); + local.setWorld(request.getWorld()); + local.setEditSession(request.getEditSession()); + try { + return Expression.this.evaluateRoot(); + } finally { + Request.reset(); + } + }); try { return result.get(timeout, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { From dcfb769d96bc4524e098e7da11811d404d41c93c Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 6 Apr 2019 13:22:20 -0400 Subject: [PATCH 007/366] Fix TrueZip region stores. I think. Someone tell me if this breaks their setup with truezip, but it works for me now and didn't before. I'm assuming people using .zip just used the normal zip store anyway. --- .../worldedit/world/storage/TrueZipMcRegionChunkStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java index a22818c77..8d7c03e93 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java @@ -93,11 +93,11 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore { } else { Pattern pattern = Pattern.compile(".*\\.mc[ra]$"); // World pattern - Pattern worldPattern = Pattern.compile(worldName + "\\$"); + Pattern worldPattern = Pattern.compile(worldName + "[\\\\/].*"); for (Enumeration e = zip.entries(); e.hasMoreElements(); ) { ZipEntry testEntry = e.nextElement(); // Check for world - if (worldPattern.matcher(worldName).matches()) { + if (worldPattern.matcher(testEntry.getName()).matches()) { // Check for file if (pattern.matcher(testEntry.getName()).matches()) { folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf('/')); From ec0422d682b8e5fb4e223358102e40d1e6b06b07 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 6 Apr 2019 21:26:52 -0400 Subject: [PATCH 008/366] Avoid atan2 in Location cinit. @kashike --- .../src/main/java/com/sk89q/worldedit/util/Location.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/Location.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/Location.java index ea161111b..0fa58a71f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/Location.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/Location.java @@ -48,7 +48,7 @@ public class Location { * @param extent the extent */ public Location(Extent extent) { - this(extent, Vector3.ZERO, Vector3.ZERO); + this(extent, Vector3.ZERO, 0f, 90f); } /** @@ -61,7 +61,7 @@ public class Location { * @param z the Z coordinate */ public Location(Extent extent, double x, double y, double z) { - this(extent, Vector3.at(x, y, z), Vector3.ZERO); + this(extent, Vector3.at(x, y, z), 0f, 90f); } /** @@ -72,7 +72,7 @@ public class Location { * @param position the position vector */ public Location(Extent extent, Vector3 position) { - this(extent, position, Vector3.ZERO); + this(extent, position, 0f, 90f); } /** From b5e1f3dbc30db4f3fc9e59e5178589ac3332bf5d Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 11 Apr 2019 12:39:56 +1000 Subject: [PATCH 009/366] Remove the system property check for uuidOverride (#459) as it caused a server timeout... https://pastebin.com/z5ktU8r3 --- .../java/com/sk89q/worldedit/session/SessionManager.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index 138c5f5df..e393fe115 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -243,12 +243,7 @@ public class SessionManager { * @return the key object */ protected UUID getKey(SessionKey key) { - String forcedKey = System.getProperty("worldedit.session.uuidOverride"); - if (forcedKey != null) { - return UUID.fromString(forcedKey); - } else { - return key.getUniqueId(); - } + return key.getUniqueId(); } /** From f8c4f23658a18b356087ae8a973fa04de83dbd64 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 14 Apr 2019 01:30:40 -0700 Subject: [PATCH 010/366] Partial work on biome commands, need logging replacement --- .../worldedit/command/BiomeCommands.java | 74 ++++++++----------- .../CommandPermissionsConditionGenerator.java | 7 +- .../extension/platform/CommandManager.java | 13 ++-- .../platform/CommandManagerCallable.java | 32 ++++---- 4 files changed, 60 insertions(+), 66 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index f3d9e9694..a1df6dcb5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -19,17 +19,11 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.function.FlatRegionFunction; @@ -46,11 +40,14 @@ import com.sk89q.worldedit.regions.FlatRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Regions; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeData; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.registry.BiomeRegistry; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; import java.util.Collection; import java.util.HashSet; @@ -59,33 +56,27 @@ import java.util.Set; /** * Implements biome-related commands such as "/biomelist". */ +@CommandContainer public class BiomeCommands { - private final WorldEdit worldEdit; - /** * Create a new instance. - * - * @param worldEdit reference to WorldEdit */ - public BiomeCommands(WorldEdit worldEdit) { - checkNotNull(worldEdit); - this.worldEdit = worldEdit; + public BiomeCommands() { } @Command( - aliases = { "biomelist", "biomels" }, - usage = "[page]", - desc = "Gets all biomes available.", - max = 1 + name = "biomelist", + aliases = { "biomels" }, + desc = "Gets all biomes available." ) @CommandPermissions("worldedit.biome.list") - public void biomeList(Player player, CommandContext args) throws WorldEditException { - int page; + public void biomeList(Player player, + @Arg(desc = "Page number.", def = "0") int page) throws WorldEditException { int offset; int count = 0; - if (args.argsLength() == 0 || (page = args.getInteger(0)) < 2) { + if (page < 2) { page = 1; offset = 0; } else { @@ -115,24 +106,24 @@ public class BiomeCommands { } @Command( - aliases = { "biomeinfo" }, - flags = "pt", + name = "biomeinfo", desc = "Get the biome of the targeted block.", - help = - "Get the biome of the block.\n" + - "By default use all the blocks contained in your selection.\n" + - "-t use the block you are looking at.\n" + - "-p use the block you are currently in", - max = 0 + descFooter = "By default, uses all blocks in your selection." ) @CommandPermissions("worldedit.biome.info") - public void biomeInfo(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void biomeInfo(Player player, LocalSession session, + @Switch( + name = 't', desc="Use the block you are looking at." + ) boolean useLineOfSight, + @Switch( + name = 'p', desc="Use the block you are currently in." + ) boolean usePosition) throws WorldEditException { BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); Set biomes = new HashSet<>(); String qualifier; - if (args.hasFlag('t')) { + if (useLineOfSight) { Location blockPosition = player.getBlockTrace(300); if (blockPosition == null) { player.printError("No block in sight!"); @@ -143,7 +134,7 @@ public class BiomeCommands { biomes.add(biome); qualifier = "at line of sight point"; - } else if (args.hasFlag('p')) { + } else if (usePosition) { BiomeType biome = player.getWorld().getBiome(player.getLocation().toVector().toBlockPoint().toBlockVector2()); biomes.add(biome); @@ -177,18 +168,15 @@ public class BiomeCommands { } @Command( - aliases = { "/setbiome" }, - usage = "", - flags = "p", - desc = "Sets the biome of the player's current block or region.", - help = - "Set the biome of the region.\n" + - "By default use all the blocks contained in your selection.\n" + - "-p use the block you are currently in" + name = "/setbiome", + desc = "Sets the biome of the player's current block or region.", + descFooter = "By default, uses all the blocks in your selection" ) - @Logging(REGION) +// @Logging(REGION) @CommandPermissions("worldedit.biome.set") - public void setBiome(Player player, LocalSession session, EditSession editSession, BiomeType target, @Switch('p') boolean atPosition) throws WorldEditException { + public void setBiome(Player player, LocalSession session, EditSession editSession, + BiomeType target, + @Switch(name = 'p', desc = "Use your current position") boolean atPosition) throws WorldEditException { World world = player.getWorld(); Region region; Mask mask = editSession.getMask(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java index d00d286d6..84011e0ff 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java @@ -41,9 +41,8 @@ public class CommandPermissionsConditionGenerator implements CommandConditionGen CommandPermissions annotation = commandMethod.getAnnotation(CommandPermissions.class); checkNotNull(annotation, "Annotation is missing from commandMethod"); Set permissions = ImmutableSet.copyOf(annotation.value()); - return p -> { - Actor actor = p.injectedValue(ACTOR_KEY); - return permissions.stream().anyMatch(actor::hasPermission); - }; + return p -> p.injectedValue(ACTOR_KEY) + .map(actor -> permissions.stream().anyMatch(actor::hasPermission)) + .orElse(false); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index 9a2a9da78..da697d182 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -145,7 +145,7 @@ public final class CommandManager { dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new BiomeCommands(worldEdit)) + .registerMethods(new BiomeCommands()) .registerMethods(new ChunkCommands(worldEdit)) .registerMethods(new ClipboardCommands(worldEdit)) .registerMethods(new GeneralCommands(worldEdit)) @@ -198,11 +198,12 @@ public final class CommandManager { desc.setPermissions(ImmutableList.of()); org.enginehub.piston.CommandManager manager = DefaultCommandManagerService.getInstance() .newCommandManager(); - new SchematicCommandsRegistration( - manager, - new SchematicCommands(worldEdit), - new CommandPermissionsConditionGenerator() - ); + SchematicCommandsRegistration.builder() + .commandManager(manager) + .containerInstance(new SchematicCommands(worldEdit)) + .commandPermissionsConditionGenerator( + new CommandPermissionsConditionGenerator() + ).build(); return new CommandManagerCallable(worldEdit, manager, desc); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java index bb6079713..fe22518ef 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java @@ -33,6 +33,7 @@ import org.enginehub.piston.CommandManager; import java.util.Collections; import java.util.List; +import java.util.Optional; /** * Hack to get {@link CommandManager} working under {@link CommandCallable}. @@ -51,20 +52,25 @@ public class CommandManagerCallable implements CommandCallable { @Override public Object call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException { - manager.injectValue(Key.get(Actor.class), () -> locals.get(Actor.class)); - manager.injectValue(Key.get(Player.class), () -> getPlayer(locals)); - manager.injectValue(Key.get(LocalSession.class), () -> { - Player sender = getPlayer(locals); - return worldEdit.getSessionManager().get(sender); - }); - manager.injectValue(Key.get(EditSession.class), () -> { - Player sender = getPlayer(locals); - LocalSession session = worldEdit.getSessionManager().get(sender); - EditSession editSession = session.createEditSession(sender); - editSession.enableStandardMode(); - session.tellVersion(sender); - return editSession; + manager.injectValue(Key.get(Actor.class), access -> Optional.of(locals.get(Actor.class))); + manager.injectValue(Key.get(Player.class), access -> { + Actor actor = locals.get(Actor.class); + return actor instanceof Player ? Optional.of(((Player) actor)) : Optional.empty(); }); + manager.injectValue(Key.get(LocalSession.class), access -> + access.injectedValue(Key.get(Player.class)) + .map(worldEdit.getSessionManager()::get) + ); + manager.injectValue(Key.get(EditSession.class), access -> + access.injectedValue(Key.get(Player.class)) + .map(sender -> { + LocalSession session = worldEdit.getSessionManager().get(sender); + EditSession editSession = session.createEditSession(sender); + editSession.enableStandardMode(); + session.tellVersion(sender); + return editSession; + }) + ); return manager.execute(Splitter.on(' ').splitToList(arguments)); } From da35b3c1741d996f39431c0b6add1ad099c136dc Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 14 Apr 2019 01:53:04 -0700 Subject: [PATCH 011/366] Switch to using local maven for Piston --- settings.gradle | 2 -- worldedit-core/build.gradle | 15 +++++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/settings.gradle b/settings.gradle index 6b725d8d1..84bd77d7d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,3 @@ rootProject.name = 'worldedit' include 'worldedit-core', 'worldedit-bukkit', 'worldedit-forge', 'worldedit-sponge' - -includeBuild("../Piston") diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index 5f6cce5a6..bfd0aac32 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -13,6 +13,11 @@ configurations.all { Configuration it -> } } +repositories { + // temporary, for Piston + mavenLocal() +} + dependencies { compile 'de.schlichtherle:truezip:6.8.3' compile 'rhino:js:1.7R2' @@ -25,10 +30,12 @@ dependencies { compile 'com.sk89q.lib:jlibnoise:1.0.0' compile 'com.googlecode.json-simple:json-simple:1.1.1' compile 'org.slf4j:slf4j-api:1.7.26' - compileOnly 'org.enginehub.piston:core-ap-annotations:0.0.1-SNAPSHOT' - compile 'org.enginehub.piston:core-ap-runtime:0.0.1-SNAPSHOT' - annotationProcessor 'org.enginehub.piston:core-ap-processor:0.0.1-SNAPSHOT' - compile 'org.enginehub.piston:default-impl:0.0.1-SNAPSHOT' + + def pistonVersion = '0.0.1-SNAPSHOT' + compileOnly "org.enginehub.piston.core-ap:annotations:$pistonVersion" + compile "org.enginehub.piston.core-ap:runtime:$pistonVersion" + annotationProcessor "org.enginehub.piston.core-ap:processor:$pistonVersion" + compile "org.enginehub.piston:default-impl:$pistonVersion" //compile 'net.sf.trove4j:trove4j:3.0.3' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } From 3e4004ad9e3376c4a30ab7d53a29eb4a4228cb54 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sun, 14 Apr 2019 19:33:44 +1000 Subject: [PATCH 012/366] Start work on improving the formatting system. May switch to Kashike's as Bukkit is shit --- .../worldedit/bukkit/BukkitCommandSender.java | 7 ++ .../sk89q/worldedit/bukkit/BukkitPlayer.java | 7 ++ .../worldedit/extension/platform/Actor.java | 8 ++ .../extension/platform/PlayerProxy.java | 6 ++ .../util/formatting/ColorCodeBuilder.java | 3 + .../worldedit/util/formatting/Fragment.java | 31 +++++++- .../worldedit/util/formatting/Style.java | 4 +- .../worldedit/util/formatting/StyleSet.java | 75 ++++++++++++++++++- .../util/formatting/StyledFragment.java | 31 +------- .../util/formatting/component/Error.java | 37 +++++++++ 10 files changed, 173 insertions(+), 36 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java index 55929af02..7f48b193d 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.util.formatting.Fragment; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -91,6 +92,12 @@ public class BukkitCommandSender implements Actor { } } + @Override + public void print(Fragment fragment) { + // TODO Bukkit is bad and the API is somewhat lacking + printRaw(fragment.toString()); + } + @Override public boolean canDestroyBedrock() { return true; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index d814cc7ba..8ef240f2c 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.formatting.Fragment; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -125,6 +126,12 @@ public class BukkitPlayer extends AbstractPlayerActor { } } + @Override + public void print(Fragment fragment) { + // TODO Bukkit is bad and the API is somewhat lacking + printRaw(fragment.toString()); + } + @Override public void setPosition(Vector3 pos, float pitch, float yaw) { player.teleport(new Location(player.getWorld(), pos.getX(), pos.getY(), diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java index cf64b5974..c5fb1b6b1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionOwner; import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.auth.Subject; +import com.sk89q.worldedit.util.formatting.Fragment; import java.io.File; @@ -75,6 +76,13 @@ public interface Actor extends Identifiable, SessionOwner, Subject { */ void printError(String msg); + /** + * Print a {@link Fragment}. + * + * @param fragment The fragment to print + */ + void print(Fragment fragment); + /** * Returns true if the actor can destroy bedrock. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java index 48173abbc..54700aeea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.Fragment; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.gamemode.GameMode; @@ -132,6 +133,11 @@ class PlayerProxy extends AbstractPlayerActor { basePlayer.printError(msg); } + @Override + public void print(Fragment fragment) { + basePlayer.print(fragment); + } + @Override public String[] getGroups() { return permActor.getGroups(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/ColorCodeBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/ColorCodeBuilder.java index dbaa904ce..14e8ddbca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/ColorCodeBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/ColorCodeBuilder.java @@ -90,6 +90,9 @@ public class ColorCodeBuilder { if (style.isStrikethrough()) { builder.append(Style.STRIKETHROUGH); } + if (style.isObfuscated()) { + builder.append(Style.OBFUSCATED); + } return builder.toString(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Fragment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Fragment.java index 3d1add7f4..e49d7c678 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Fragment.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Fragment.java @@ -19,16 +19,45 @@ package com.sk89q.worldedit.util.formatting; +import java.util.ArrayList; +import java.util.List; + /** * A fragment of text. */ public class Fragment { private final StringBuilder builder = new StringBuilder(); - + private final List children = new ArrayList<>(); + private Fragment lastText; + Fragment() { } + public List getChildren() { + return children; + } + + protected Fragment lastText() { + Fragment text; + if (!children.isEmpty()) { + text = children.get(children.size() - 1); + if (text == lastText) { + return text; + } + } + + text = new Fragment(); + this.lastText = text; + children.add(text); + return text; + } + + public Fragment append(Fragment fragment) { + children.add(fragment); + return this; + } + public Fragment append(String str) { builder.append(Style.stripColor(str)); return this; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Style.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Style.java index d6c70eeb8..d81774009 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Style.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Style.java @@ -29,8 +29,6 @@ import java.util.regex.Pattern; /** * All supported color values for chat. - * - *

From Bukkit.

*/ public enum Style { /** @@ -100,7 +98,7 @@ public enum Style { /** * Represents magical characters that change around randomly */ - RANDOMIZE('k', 0x10, true), + OBFUSCATED('k', 0x10, true), /** * Makes the text bold. */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyleSet.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyleSet.java index 408dc1e43..2a1c0cf46 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyleSet.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyleSet.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.util.formatting; +import java.util.Objects; + /** * Represents set of styles, such as color, bold, etc. */ @@ -28,6 +30,8 @@ public class StyleSet { private Boolean italic; private Boolean underline; private Boolean strikethrough; + private Boolean obfuscated; + private String insertion; private Style color; /** @@ -55,6 +59,8 @@ public class StyleSet { underline = true; } else if (style == Style.STRIKETHROUGH) { strikethrough = true; + } else if (style == Style.OBFUSCATED) { + obfuscated = true; } } } @@ -167,6 +173,60 @@ public class StyleSet { this.strikethrough = strikethrough; } + /** + * Get whether this style set is obfuscated. + * + * @return true, false, or null if unset + */ + public Boolean getObfuscated() { + return obfuscated; + } + + /** + * Get whether this style set is obfuscated. + * + * @return true if there is obfuscation applied + */ + public boolean isObfuscated() { + return getObfuscated() != null && getObfuscated(); + } + + /** + * Set whether the text is obfuscated. + * + * @param obfuscated false, or null to unset + */ + public void setObfuscated(Boolean obfuscated) { + this.obfuscated = obfuscated; + } + + /** + * Get this style set's insertion, if present. + * + * @return the insertion, or null if unset + */ + public String getInsertion() { + return insertion; + } + + /** + * Get whether this style set has an insertion. + * + * @return true if there is an insertion + */ + public boolean hasInsertion() { + return insertion != null; + } + + /** + * Set the style set's insertion. + * + * @param insertion the insertion, or null to unset + */ + public void setInsertion(String insertion) { + this.insertion = insertion; + } + /** * Get the color of the text. * @@ -192,7 +252,8 @@ public class StyleSet { */ public boolean hasFormatting() { return getBold() != null || getItalic() != null - || getUnderline() != null || getStrikethrough() != null; + || getUnderline() != null || getStrikethrough() != null + || getObfuscated() != null || getInsertion() != null; } /** @@ -205,7 +266,9 @@ public class StyleSet { public boolean hasEqualFormatting(StyleSet other) { return getBold() == other.getBold() && getItalic() == other.getItalic() && getUnderline() == other.getUnderline() && - getStrikethrough() == other.getStrikethrough(); + getStrikethrough() == other.getStrikethrough() && + getObfuscated() == other.getObfuscated() && + Objects.equals(getInsertion(), other.getInsertion()); } /** @@ -229,6 +292,12 @@ public class StyleSet { if (style.getStrikethrough() != null) { newStyle.setStrikethrough(style.getStrikethrough()); } + if (style.getObfuscated() != null) { + newStyle.setObfuscated(style.getObfuscated()); + } + if (style.getInsertion() != null) { + newStyle.setInsertion(style.getInsertion()); + } if (style.getColor() != null) { newStyle.setColor(style.getColor()); } @@ -242,6 +311,8 @@ public class StyleSet { style.setItalic(getItalic()); style.setUnderline(getUnderline()); style.setStrikethrough(getStrikethrough()); + style.setObfuscated(getObfuscated()); + style.setInsertion(getInsertion()); style.setColor(getColor()); return style; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyledFragment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyledFragment.java index 9ef38446b..ec0578d47 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyledFragment.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyledFragment.java @@ -19,18 +19,13 @@ package com.sk89q.worldedit.util.formatting; -import java.util.ArrayList; -import java.util.List; - /** * A fragment of text that can be styled. */ public class StyledFragment extends Fragment { - private final List children = new ArrayList<>(); private StyleSet style; - private Fragment lastText; - + public StyledFragment() { style = new StyleSet(); } @@ -51,36 +46,12 @@ public class StyledFragment extends Fragment { this.style = style; } - public List getChildren() { - return children; - } - - protected Fragment lastText() { - Fragment text; - if (!children.isEmpty()) { - text = children.get(children.size() - 1); - if (text == lastText) { - return text; - } - } - - text = new Fragment(); - this.lastText = text; - children.add(text); - return text; - } - public StyledFragment createFragment(Style... styles) { StyledFragment fragment = new StyledFragment(styles); append(fragment); return fragment; } - public StyledFragment append(StyledFragment fragment) { - children.add(fragment); - return this; - } - @Override public StyledFragment append(String str) { lastText().append(str); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java new file mode 100644 index 000000000..056c99c18 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java @@ -0,0 +1,37 @@ +/* + * 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.util.formatting.component; + +import com.sk89q.worldedit.util.formatting.Style; +import com.sk89q.worldedit.util.formatting.StyledFragment; + +/** + * Represents a fragment representing an error. + */ +public class Error extends StyledFragment { + + /** + * Create a new instance. + */ + public Error() { + super(Style.RED); + } + +} From 2a1fdf470f9fd52a9c20b09e6c755ba9bd105491 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 14 Apr 2019 11:16:49 -0400 Subject: [PATCH 013/366] Implement getMaxY for ForgeWorld. Should play nicer with things like CubicChunks. Note that there is no way to get the min point in Minecraft itself, so this only supports going up, not down. --- .../src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 43a9399b9..5dbdc09f6 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -426,6 +426,11 @@ public class ForgeWorld extends AbstractWorld { } } + @Override + public int getMaxY() { + return getWorld().getHeight(); + } + @Override public BlockVector3 getSpawnPosition() { return ForgeAdapter.adapt(getWorld().getSpawnPoint()); From 267ccf2298d31c2a5e00dd232f0c3aa04c9e93c2 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Apr 2019 01:21:15 -0700 Subject: [PATCH 014/366] First attempt at integrating Piston as the only command system --- build.gradle | 2 + .../bukkit/BukkitCommandInspector.java | 41 ++-- .../bukkit/BukkitServerInterface.java | 36 ++-- .../worldedit/bukkit/WorldEditListener.java | 31 +-- worldedit-core/build.gradle | 11 +- .../worldedit/command/UtilityCommands.java | 23 ++- .../worldedit/command/WorldEditCommands.java | 2 +- .../worldedit/command/argument/Arguments.java | 31 +++ .../command/argument/EditSessionHolder.java | 87 +++++++++ .../command/composition/SelectionCommand.java | 2 +- .../composition/ShapedBrushCommand.java | 2 +- .../CommandPermissionsConditionGenerator.java | 6 +- .../command/util/MessageFutureCallback.java | 2 +- .../command/util/PermissionCondition.java | 49 +++++ .../extension/platform/Capability.java | 4 +- .../platform/CommandManagerCallable.java | 96 ---------- .../extension/platform/Platform.java | 7 +- ...ager.java => PlatformCommandMananger.java} | 177 +++++++++--------- .../extension/platform/PlatformManager.java | 8 +- .../command/CommandLoggingHandler.java | 113 +++++------ .../command/WorldEditExceptionConverter.java | 49 +++-- .../parametric/ExceptionConverter.java | 7 +- .../parametric/ExceptionConverterHelper.java | 7 +- .../formatting/component/CommandUsageBox.java | 4 +- .../sk89q/worldedit/forge/CommandWrapper.java | 22 ++- .../sk89q/worldedit/forge/ForgePlatform.java | 22 ++- .../worldedit/sponge/CommandAdapter.java | 24 ++- .../worldedit/sponge/SpongePlatform.java | 17 +- 28 files changed, 493 insertions(+), 389 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EditSessionHolder.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java rename worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/{CommandManager.java => PlatformCommandMananger.java} (72%) diff --git a/build.gradle b/build.gradle index 8bdb1a122..41c04e0bd 100644 --- a/build.gradle +++ b/build.gradle @@ -101,6 +101,8 @@ subprojects { mavenCentral() maven { url "http://maven.sk89q.com/repo/" } maven { url "http://repo.maven.apache.org/maven2" } + // temporary, for Piston + mavenLocal() } if (JavaVersion.current().isJava8Compatible()) { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java index fa3f2917f..917d31981 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java @@ -19,26 +19,29 @@ package com.sk89q.worldedit.bukkit; +import com.google.common.collect.ImmutableMap; +import com.google.inject.Key; import com.sk89q.bukkit.util.CommandInspector; -import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.util.command.CommandMapping; -import com.sk89q.worldedit.util.command.Description; -import com.sk89q.worldedit.util.command.Dispatcher; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.NoInputCommandParameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Optional; + import static com.google.common.base.Preconditions.checkNotNull; class BukkitCommandInspector implements CommandInspector { private static final Logger logger = LoggerFactory.getLogger(BukkitCommandInspector.class); private final WorldEditPlugin plugin; - private final Dispatcher dispatcher; + private final CommandManager dispatcher; - BukkitCommandInspector(WorldEditPlugin plugin, Dispatcher dispatcher) { + BukkitCommandInspector(WorldEditPlugin plugin, CommandManager dispatcher) { checkNotNull(plugin); checkNotNull(dispatcher); this.plugin = plugin; @@ -47,9 +50,9 @@ class BukkitCommandInspector implements CommandInspector { @Override public String getShortText(Command command) { - CommandMapping mapping = dispatcher.get(command.getName()); - if (mapping != null) { - return mapping.getDescription().getDescription(); + Optional mapping = dispatcher.getCommand(command.getName()); + if (mapping.isPresent()) { + return mapping.get().getDescription(); } else { logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'"); return "Help text not available"; @@ -58,10 +61,9 @@ class BukkitCommandInspector implements CommandInspector { @Override public String getFullText(Command command) { - CommandMapping mapping = dispatcher.get(command.getName()); - if (mapping != null) { - Description description = mapping.getDescription(); - return "Usage: " + description.getUsage() + (description.getHelp() != null ? "\n" + description.getHelp() : ""); + Optional mapping = dispatcher.getCommand(command.getName()); + if (mapping.isPresent()) { + return mapping.get().getFullHelp(); } else { logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'"); return "Help text not available"; @@ -70,11 +72,14 @@ class BukkitCommandInspector implements CommandInspector { @Override public boolean testPermission(CommandSender sender, Command command) { - CommandMapping mapping = dispatcher.get(command.getName()); - if (mapping != null) { - CommandLocals locals = new CommandLocals(); - locals.put(Actor.class, plugin.wrapCommandSender(sender)); - return mapping.getCallable().testPermission(locals); + Optional mapping = dispatcher.getCommand(command.getName()); + if (mapping.isPresent()) { + CommandParameters parameters = NoInputCommandParameters.builder() + .injectedValues(ImmutableMap.of( + Key.get(Actor.class), plugin.wrapCommandSender(sender) + )) + .build(); + return mapping.get().getCondition().satisfied(parameters); } else { logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'"); return false; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index adfc64bc0..e24714821 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -22,27 +22,28 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.bukkit.util.CommandInfo; import com.sk89q.bukkit.util.CommandRegistration; import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; import com.sk89q.worldedit.util.command.CommandMapping; -import com.sk89q.worldedit.util.command.Description; -import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.world.registry.Registries; import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.World; import org.bukkit.entity.EntityType; +import org.enginehub.piston.CommandManager; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; import java.util.List; import java.util.Map; - -import javax.annotation.Nullable; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class BukkitServerInterface implements MultiUserPlatform { public Server server; @@ -116,20 +117,25 @@ public class BukkitServerInterface implements MultiUserPlatform { } @Override - public void registerCommands(Dispatcher dispatcher) { - List toRegister = new ArrayList<>(); + public void registerCommands(CommandManager dispatcher) { BukkitCommandInspector inspector = new BukkitCommandInspector(plugin, dispatcher); - - for (CommandMapping command : dispatcher.getCommands()) { - Description description = command.getDescription(); - List permissions = description.getPermissions(); - String[] permissionsArray = new String[permissions.size()]; - permissions.toArray(permissionsArray); - toRegister.add(new CommandInfo(description.getUsage(), description.getDescription(), command.getAllAliases(), inspector, permissionsArray)); - } + dynamicCommands.register(dispatcher.getAllCommands() + .map(command -> { + String[] permissionsArray = command.getCondition() + .as(PermissionCondition.class) + .map(PermissionCondition::getPermissions) + .map(s -> s.toArray(new String[0])) + .orElseGet(() -> new String[0]); - dynamicCommands.register(toRegister); + String[] aliases = Stream.concat( + Stream.of(command.getName()), + command.getAliases().stream() + ).toArray(String[]::new); + return new CommandInfo(command.getUsage(), + command.getDescription(), aliases, + inspector, permissionsArray); + }).collect(Collectors.toList())); } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java index 05774b84c..9c124f83f 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java @@ -21,13 +21,13 @@ package com.sk89q.worldedit.bukkit; -import com.sk89q.minecraft.util.commands.CommandLocals; +import com.google.common.collect.ImmutableMap; +import com.google.inject.Key; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.world.World; import org.bukkit.block.Block; import org.bukkit.event.Event.Result; @@ -40,9 +40,9 @@ import org.bukkit.event.player.PlayerCommandSendEvent; import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; - -import java.util.Set; -import java.util.stream.Collectors; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.NoInputCommandParameters; /** * Handles all events thrown in relation to a Player @@ -87,7 +87,7 @@ public class WorldEditListener implements Listener { if (split.length > 0) { split[0] = split[0].substring(1); - split = plugin.getWorldEdit().getPlatformManager().getCommandManager().commandDetection(split); + split = plugin.getWorldEdit().getPlatformManager().getPlatformCommandMananger().commandDetection(split); } final String newMessage = "/" + StringUtil.joinString(split, " "); @@ -108,13 +108,18 @@ public class WorldEditListener implements Listener { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onPlayerCommand(PlayerCommandSendEvent event) { - CommandLocals locals = new CommandLocals(); - locals.put(Actor.class, plugin.wrapCommandSender(event.getPlayer())); - Set toRemove = plugin.getWorldEdit().getPlatformManager().getCommandManager().getDispatcher().getCommands().stream() - .filter(commandMapping -> !commandMapping.getCallable().testPermission(locals)) - .map(CommandMapping::getPrimaryAlias) - .collect(Collectors.toSet()); - event.getCommands().removeIf(toRemove::contains); + CommandParameters parameters = NoInputCommandParameters.builder() + .injectedValues(ImmutableMap.of( + Key.get(Actor.class), plugin.wrapCommandSender(event.getPlayer()) + )) + .build(); + CommandManager commandManager = plugin.getWorldEdit().getPlatformManager().getPlatformCommandMananger().getCommandManager(); + event.getCommands().removeIf(name -> + // remove if in the manager and not satisfied + commandManager.getCommand(name) + .filter(command -> !command.getCondition().satisfied(parameters)) + .isPresent() + ); } /** diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index bfd0aac32..23f96a592 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -2,6 +2,7 @@ plugins { id("net.ltgt.apt") version "0.21" } +apply plugin: 'java-library' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'net.ltgt.apt-eclipse' @@ -13,11 +14,6 @@ configurations.all { Configuration it -> } } -repositories { - // temporary, for Piston - mavenLocal() -} - dependencies { compile 'de.schlichtherle:truezip:6.8.3' compile 'rhino:js:1.7R2' @@ -32,10 +28,11 @@ dependencies { compile 'org.slf4j:slf4j-api:1.7.26' def pistonVersion = '0.0.1-SNAPSHOT' + api "org.enginehub.piston:core:$pistonVersion" compileOnly "org.enginehub.piston.core-ap:annotations:$pistonVersion" - compile "org.enginehub.piston.core-ap:runtime:$pistonVersion" + implementation "org.enginehub.piston.core-ap:runtime:$pistonVersion" annotationProcessor "org.enginehub.piston.core-ap:processor:$pistonVersion" - compile "org.enginehub.piston:default-impl:$pistonVersion" + api "org.enginehub.piston:default-impl:$pistonVersion" //compile 'net.sf.trove4j:trove4j:3.0.3' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 8768be6c8..415b77adf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -39,7 +39,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.extension.platform.CommandManager; +import com.sk89q.worldedit.extension.platform.PlatformCommandMananger; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.BlockPattern; @@ -67,6 +67,7 @@ import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; +import org.enginehub.piston.CommandManager; import java.util.ArrayList; import java.util.List; @@ -598,7 +599,10 @@ public class UtilityCommands { } public static void help(CommandContext args, WorldEdit we, Actor actor) { - CommandCallable callable = we.getPlatformManager().getCommandManager().getDispatcher(); + CommandManager manager = we.getPlatformManager().getPlatformCommandMananger().getCommandManager(); + + // TODO this will be implemented as a special utility in the manager + /* int page = 0; final int perPage = actor instanceof Player ? 8 : 20; // More pages for console @@ -626,15 +630,15 @@ public class UtilityCommands { for (int i = 0; i < effectiveLength; i++) { String command = args.getString(i); - if (callable instanceof Dispatcher) { + if (manager instanceof Dispatcher) { // Chop off the beginning / if we're are the root level if (isRootLevel && command.length() > 1 && command.charAt(0) == '/') { command = command.substring(1); } - CommandMapping mapping = detectCommand((Dispatcher) callable, command, isRootLevel); + CommandMapping mapping = detectCommand((Dispatcher) manager, command, isRootLevel); if (mapping != null) { - callable = mapping.getCallable(); + manager = mapping.getCallable(); } else { if (isRootLevel) { actor.printError(String.format("The command '%s' could not be found.", args.getString(i))); @@ -656,12 +660,12 @@ public class UtilityCommands { } // Create the message - if (callable instanceof Dispatcher) { - Dispatcher dispatcher = (Dispatcher) callable; + if (manager instanceof Dispatcher) { + Dispatcher dispatcher = (Dispatcher) manager; // Get a list of aliases List aliases = new ArrayList<>(dispatcher.getCommands()); - aliases.sort(new PrimaryAliasComparator(CommandManager.COMMAND_CLEAN_PATTERN)); + aliases.sort(new PrimaryAliasComparator(PlatformCommandMananger.COMMAND_CLEAN_PATTERN)); // Calculate pagination int offset = perPage * page; @@ -698,9 +702,10 @@ public class UtilityCommands { actor.printRaw(ColorCodeBuilder.asColorCodes(box)); } else { - CommandUsageBox box = new CommandUsageBox(callable, Joiner.on(" ").join(visited)); + CommandUsageBox box = new CommandUsageBox(manager, Joiner.on(" ").join(visited)); actor.printRaw(ColorCodeBuilder.asColorCodes(box)); } + */ } } 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 26c382beb..787859323 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 @@ -113,7 +113,7 @@ public class WorldEditCommands { actor.checkPermission("worldedit.report.pastebin"); ActorCallbackPaste.pastebin( we.getSupervisor(), actor, result, "WorldEdit report: %s.report", - WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter() + WorldEdit.getInstance().getPlatformManager().getPlatformCommandMananger().getExceptionConverter() ); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java new file mode 100644 index 000000000..1bf5fc4e9 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java @@ -0,0 +1,31 @@ +/* + * 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.command.argument; + +import org.enginehub.piston.InjectedValueAccess; + +/** + * Key-interface for {@link InjectedValueAccess} for the String arguments. + */ +public interface Arguments { + + String get(); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EditSessionHolder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EditSessionHolder.java new file mode 100644 index 000000000..b5113f545 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EditSessionHolder.java @@ -0,0 +1,87 @@ +/* + * 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.command.argument; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; + +import java.util.concurrent.locks.StampedLock; + +/** + * Lazily-created {@link EditSession}. + */ +public class EditSessionHolder { + + private final StampedLock lock = new StampedLock(); + private final WorldEdit worldEdit; + private final Player player; + + public EditSessionHolder(WorldEdit worldEdit, Player player) { + this.worldEdit = worldEdit; + this.player = player; + } + + private EditSession session; + + /** + * Get the session, but does not create it if it doesn't exist. + */ + public EditSession getSession() { + long stamp = lock.tryOptimisticRead(); + EditSession result = session; + if (!lock.validate(stamp)) { + stamp = lock.readLock(); + try { + result = session; + } finally { + lock.unlockRead(stamp); + } + } + return result; + } + + public EditSession getOrCreateSession() { + // use the already-generated result if possible + EditSession result = getSession(); + if (result != null) { + return result; + } + // otherwise, acquire write lock + long stamp = lock.writeLock(); + try { + // check session field again -- maybe another writer hit it in between + result = session; + if (result != null) { + return result; + } + // now we can do the actual creation + LocalSession localSession = worldEdit.getSessionManager().get(player); + EditSession editSession = localSession.createEditSession(player); + editSession.enableStandardMode(); + localSession.tellVersion(player); + return session = editSession; + } finally { + lock.unlockWrite(stamp); + } + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java index a8e89e364..dd51c64a2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java @@ -94,7 +94,7 @@ public class SelectionCommand extends SimpleCommand { return operation; } catch (IncompleteRegionException e) { - WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter().convert(e); + WorldEdit.getInstance().getPlatformManager().getPlatformCommandMananger().getExceptionConverter().convert(e); return null; } } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java index 98daedde2..35fb758a3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java @@ -77,7 +77,7 @@ public class ShapedBrushCommand extends SimpleCommand { tool.setFill(null); tool.setBrush(new OperationFactoryBrush(factory, regionFactory, session), permission); } catch (MaxBrushRadiusException | InvalidToolBindException e) { - WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter().convert(e); + WorldEdit.getInstance().getPlatformManager().getPlatformCommandMananger().getExceptionConverter().convert(e); } player.print("Set brush to " + factory); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java index 84011e0ff..28041a1a1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java @@ -34,15 +34,11 @@ import static com.google.common.base.Preconditions.checkNotNull; @NonnullByDefault public class CommandPermissionsConditionGenerator implements CommandConditionGenerator { - private static final Key ACTOR_KEY = Key.get(Actor.class); - @Override public Command.Condition generateCondition(Method commandMethod) { CommandPermissions annotation = commandMethod.getAnnotation(CommandPermissions.class); checkNotNull(annotation, "Annotation is missing from commandMethod"); Set permissions = ImmutableSet.copyOf(annotation.value()); - return p -> p.injectedValue(ACTOR_KEY) - .map(actor -> permissions.stream().anyMatch(actor::hasPermission)) - .orElse(false); + return new PermissionCondition(permissions); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java index 3abb73545..58b25770d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java @@ -22,9 +22,9 @@ package com.sk89q.worldedit.command.util; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.util.concurrent.FutureCallback; -import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; +import org.enginehub.piston.exception.CommandException; import javax.annotation.Nullable; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java new file mode 100644 index 000000000..2d7f7cd2e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java @@ -0,0 +1,49 @@ +/* + * 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.command.util; + +import com.google.inject.Key; +import com.sk89q.worldedit.extension.platform.Actor; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandParameters; + +import java.util.Set; + +public final class PermissionCondition implements Command.Condition { + + private static final Key ACTOR_KEY = Key.get(Actor.class); + + private final Set permissions; + + PermissionCondition(Set permissions) { + this.permissions = permissions; + } + + public Set getPermissions() { + return permissions; + } + + @Override + public boolean satisfied(CommandParameters parameters) { + return parameters.injectedValue(ACTOR_KEY) + .map(actor -> permissions.stream().anyMatch(actor::hasPermission)) + .orElse(false); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java index a753b0fd2..50aa913b4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java @@ -50,12 +50,12 @@ public enum Capability { USER_COMMANDS { @Override void initialize(PlatformManager platformManager, Platform platform) { - platformManager.getCommandManager().register(platform); + platformManager.getPlatformCommandMananger().register(platform); } @Override void unload(PlatformManager platformManager, Platform platform) { - platformManager.getCommandManager().unregister(); + platformManager.getPlatformCommandMananger().unregister(); } }, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java deleted file mode 100644 index fe22518ef..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManagerCallable.java +++ /dev/null @@ -1,96 +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 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.extension.platform; - -import com.google.common.base.Splitter; -import com.google.inject.Key; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.util.command.CommandCallable; -import com.sk89q.worldedit.util.command.Description; -import org.enginehub.piston.CommandManager; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -/** - * Hack to get {@link CommandManager} working under {@link CommandCallable}. - */ -public class CommandManagerCallable implements CommandCallable { - - private final WorldEdit worldEdit; - private final CommandManager manager; - private final Description description; - - public CommandManagerCallable(WorldEdit worldEdit, CommandManager manager, Description description) { - this.worldEdit = worldEdit; - this.manager = manager; - this.description = description; - } - - @Override - public Object call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException { - manager.injectValue(Key.get(Actor.class), access -> Optional.of(locals.get(Actor.class))); - manager.injectValue(Key.get(Player.class), access -> { - Actor actor = locals.get(Actor.class); - return actor instanceof Player ? Optional.of(((Player) actor)) : Optional.empty(); - }); - manager.injectValue(Key.get(LocalSession.class), access -> - access.injectedValue(Key.get(Player.class)) - .map(worldEdit.getSessionManager()::get) - ); - manager.injectValue(Key.get(EditSession.class), access -> - access.injectedValue(Key.get(Player.class)) - .map(sender -> { - LocalSession session = worldEdit.getSessionManager().get(sender); - EditSession editSession = session.createEditSession(sender); - editSession.enableStandardMode(); - session.tellVersion(sender); - return editSession; - }) - ); - return manager.execute(Splitter.on(' ').splitToList(arguments)); - } - - private Player getPlayer(CommandLocals locals) { - Actor actor = locals.get(Actor.class); - return actor instanceof Player ? (Player) actor : null; - } - - @Override - public Description getDescription() { - return description; - } - - @Override - public boolean testPermission(CommandLocals locals) { - return true; - } - - @Override - public List getSuggestions(String arguments, CommandLocals locals) throws CommandException { - return Collections.emptyList(); - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index 3b37a98b5..ace903fe0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; +import org.enginehub.piston.CommandManager; import java.util.List; import java.util.Map; @@ -97,11 +98,11 @@ public interface Platform { @Nullable World matchWorld(World world); /** - * Register the commands contained within the given command dispatcher. + * Register the commands contained within the given command manager. * - * @param dispatcher the dispatcher + * @param commandManager the command manager */ - void registerCommands(Dispatcher dispatcher); + void registerCommands(CommandManager commandManager); /** * Register game hooks. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java similarity index 72% rename from worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index da697d182..e08c44eb5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -19,9 +19,8 @@ package com.sk89q.worldedit.extension.platform; -import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; -import com.sk89q.minecraft.util.commands.CommandException; +import com.google.inject.Key; import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.minecraft.util.commands.CommandPermissionsException; import com.sk89q.minecraft.util.commands.WrappedCommandException; @@ -30,51 +29,25 @@ import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.BiomeCommands; -import com.sk89q.worldedit.command.BrushCommands; -import com.sk89q.worldedit.command.ChunkCommands; -import com.sk89q.worldedit.command.ClipboardCommands; -import com.sk89q.worldedit.command.GeneralCommands; -import com.sk89q.worldedit.command.GenerationCommands; -import com.sk89q.worldedit.command.HistoryCommands; -import com.sk89q.worldedit.command.NavigationCommands; -import com.sk89q.worldedit.command.RegionCommands; +import com.sk89q.worldedit.command.BiomeCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; -import com.sk89q.worldedit.command.ScriptingCommands; -import com.sk89q.worldedit.command.SelectionCommands; -import com.sk89q.worldedit.command.SnapshotCommands; -import com.sk89q.worldedit.command.SnapshotUtilCommands; -import com.sk89q.worldedit.command.SuperPickaxeCommands; -import com.sk89q.worldedit.command.ToolCommands; -import com.sk89q.worldedit.command.ToolUtilCommands; -import com.sk89q.worldedit.command.UtilityCommands; -import com.sk89q.worldedit.command.WorldEditCommands; -import com.sk89q.worldedit.command.argument.ReplaceParser; -import com.sk89q.worldedit.command.argument.TreeGeneratorParser; -import com.sk89q.worldedit.command.composition.ApplyCommand; -import com.sk89q.worldedit.command.composition.DeformCommand; -import com.sk89q.worldedit.command.composition.PaintCommand; -import com.sk89q.worldedit.command.composition.SelectionCommand; -import com.sk89q.worldedit.command.composition.ShapedBrushCommand; +import com.sk89q.worldedit.command.argument.Arguments; +import com.sk89q.worldedit.command.argument.EditSessionHolder; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.factory.Deform; -import com.sk89q.worldedit.function.factory.Deform.Mode; import com.sk89q.worldedit.internal.command.ActorAuthorizer; -import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import com.sk89q.worldedit.internal.command.UserCommandCompleter; import com.sk89q.worldedit.internal.command.WorldEditBinding; import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; import com.sk89q.worldedit.session.request.Request; -import com.sk89q.worldedit.util.command.CommandCallable; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.InvalidUsageException; -import com.sk89q.worldedit.util.command.SimpleDescription; -import com.sk89q.worldedit.util.command.composition.ProvidedValue; -import com.sk89q.worldedit.util.command.fluent.CommandGraph; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.command.parametric.LegacyCommandsHandler; import com.sk89q.worldedit.util.command.parametric.ParametricBuilder; @@ -84,35 +57,44 @@ import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; import com.sk89q.worldedit.world.World; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; import org.enginehub.piston.DefaultCommandManagerService; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.CommandExecutionException; +import org.enginehub.piston.exception.ConditionFailedException; +import org.enginehub.piston.exception.UsageException; +import org.enginehub.piston.part.SubCommandPart; +import org.enginehub.piston.util.ValueProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; +import java.util.Optional; import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.util.command.composition.LegacyCommandAdapter.adapt; /** * Handles the registration and invocation of commands. * *

This class is primarily for internal usage.

*/ -public final class CommandManager { +public final class PlatformCommandMananger { public static final Pattern COMMAND_CLEAN_PATTERN = Pattern.compile("^[/]+"); - private static final Logger log = LoggerFactory.getLogger(CommandManager.class); + private static final Logger log = LoggerFactory.getLogger(PlatformCommandMananger.class); private static final java.util.logging.Logger commandLog = - java.util.logging.Logger.getLogger(CommandManager.class.getCanonicalName() + ".CommandLog"); + java.util.logging.Logger.getLogger(PlatformCommandMananger.class.getCanonicalName() + ".CommandLog"); private static final Pattern numberFormatExceptionPattern = Pattern.compile("^For input string: \"(.*)\"$"); private final WorldEdit worldEdit; private final PlatformManager platformManager; - private final Dispatcher dispatcher; + private final CommandManager commandManager; private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler(); private final ExceptionConverter exceptionConverter; @@ -121,12 +103,14 @@ public final class CommandManager { * * @param worldEdit the WorldEdit instance */ - CommandManager(final WorldEdit worldEdit, PlatformManager platformManager) { + PlatformCommandMananger(final WorldEdit worldEdit, PlatformManager platformManager) { checkNotNull(worldEdit); checkNotNull(platformManager); this.worldEdit = worldEdit; this.platformManager = platformManager; this.exceptionConverter = new WorldEditExceptionConverter(worldEdit); + this.commandManager = DefaultCommandManagerService.getInstance() + .newCommandManager(); // Register this instance for command events worldEdit.getEventBus().register(this); @@ -140,12 +124,41 @@ public final class CommandManager { builder.setDefaultCompleter(new UserCommandCompleter(platformManager)); builder.addBinding(new WorldEditBinding(worldEdit)); builder.addInvokeListener(new LegacyCommandsHandler()); - builder.addInvokeListener(new CommandLoggingHandler(worldEdit, commandLog)); + CommandPermissionsConditionGenerator permsGenerator = + new CommandPermissionsConditionGenerator(); + + commandManager.register("schematic", cmd -> { + cmd.aliases(ImmutableList.of("schem", "/schematic", "/schem")); + cmd.description("Schematic commands for saving/loading areas"); + cmd.action(Command.Action.NULL_ACTION); + + CommandManager manager = DefaultCommandManagerService.getInstance() + .newCommandManager(); + SchematicCommandsRegistration.builder() + .commandManager(manager) + .containerInstance(new SchematicCommands(worldEdit)) + .commandPermissionsConditionGenerator( + permsGenerator + ).build(); + + cmd.addPart(SubCommandPart.builder("action", "Sub-command to run.") + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() + .build()); + }); + + BiomeCommandsRegistration.builder() + .commandManager(commandManager) + .containerInstance(new BiomeCommands()) + .commandPermissionsConditionGenerator(permsGenerator) + .build(); + + // Unported commands are below. Delete once they're added to the main manager above. + /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new BiomeCommands()) .registerMethods(new ChunkCommands(worldEdit)) .registerMethods(new ClipboardCommands(worldEdit)) .registerMethods(new GeneralCommands(worldEdit)) @@ -164,7 +177,6 @@ public final class CommandManager { .describeAs("WorldEdit commands") .registerMethods(new WorldEditCommands(worldEdit)) .parent() - .register(schematicCommands(),"schematic", "schem", "/schematic", "/schem") .group("snapshot", "snap") .describeAs("Schematic commands for saving/loading areas") .registerMethods(new SnapshotCommands(worldEdit)) @@ -190,22 +202,7 @@ public final class CommandManager { .parent() .graph() .getDispatcher(); - } - - private CommandCallable schematicCommands() { - SimpleDescription desc = new SimpleDescription(); - desc.setDescription("Schematic commands for saving/loading areas"); - desc.setPermissions(ImmutableList.of()); - org.enginehub.piston.CommandManager manager = DefaultCommandManagerService.getInstance() - .newCommandManager(); - SchematicCommandsRegistration.builder() - .commandManager(manager) - .containerInstance(new SchematicCommands(worldEdit)) - .commandPermissionsConditionGenerator( - new CommandPermissionsConditionGenerator() - ).build(); - - return new CommandManagerCallable(worldEdit, manager, desc); + */ } public ExceptionConverter getExceptionConverter() { @@ -238,7 +235,7 @@ public final class CommandManager { dynamicHandler.setFormatter(new LogFormat(config.logFormat)); } - platform.registerCommands(dispatcher); + platform.registerCommands(commandManager); } void unregister() { @@ -258,10 +255,10 @@ public final class CommandManager { String searchCmd = split[0].toLowerCase(); // Try to detect the command - if (!dispatcher.contains(searchCmd)) { - if (worldEdit.getConfiguration().noDoubleSlash && dispatcher.contains("/" + searchCmd)) { + if (!commandManager.containsCommand(searchCmd)) { + if (worldEdit.getConfiguration().noDoubleSlash && commandManager.containsCommand("/" + searchCmd)) { split[0] = "/" + split[0]; - } else if (searchCmd.length() >= 2 && searchCmd.charAt(0) == '/' && dispatcher.contains(searchCmd.substring(1))) { + } else if (searchCmd.length() >= 2 && searchCmd.charAt(0) == '/' && commandManager.containsCommand(searchCmd.substring(1))) { split[0] = split[0].substring(1); } } @@ -277,7 +274,7 @@ public final class CommandManager { String[] split = commandDetection(event.getArguments().split(" ")); // No command found! - if (!dispatcher.contains(split[0])) { + if (!commandManager.containsCommand(split[0])) { return; } @@ -291,9 +288,13 @@ public final class CommandManager { } LocalConfiguration config = worldEdit.getConfiguration(); - CommandLocals locals = new CommandLocals(); - locals.put(Actor.class, actor); - locals.put("arguments", event.getArguments()); + commandManager.injectValue(Key.get(Actor.class), ValueProvider.constant(actor)); + commandManager.injectValue(Key.get(Arguments.class), ValueProvider.constant(event::getArguments)); + commandManager.injectValue(Key.get(EditSessionHolder.class), + context -> context.injectedValue(Key.get(Actor.class)) + .filter(Player.class::isInstance) + .map(Player.class::cast) + .map(p -> new EditSessionHolder(worldEdit, p))); long start = System.currentTimeMillis(); @@ -303,7 +304,7 @@ public final class CommandManager { // exceptions without writing a hook into every dispatcher, we need to unwrap these // exceptions and rethrow their converted form, if their is one. try { - dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]); + commandManager.execute(ImmutableList.copyOf(split)); } catch (Throwable t) { // Use the exception converter to convert the exception if any of its causes // can be converted, otherwise throw the original exception @@ -315,21 +316,14 @@ public final class CommandManager { throw t; } - } catch (CommandPermissionsException e) { - actor.printError("You are not permitted to do that. Are you in the right mode?"); - } catch (InvalidUsageException e) { - if (e.isFullHelpSuggested()) { - actor.printRaw(ColorCodeBuilder.asColorCodes(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals))); - String message = e.getMessage(); - if (message != null) { - actor.printError(message); - } - } else { - String message = e.getMessage(); - actor.printError(message != null ? message : "The command was not used properly (no more help available)."); - actor.printError("Usage: " + e.getSimpleUsageString("/")); + } catch (ConditionFailedException e) { + if (e.getCondition() instanceof PermissionCondition) { + actor.printError("You are not permitted to do that. Are you in the right mode?"); } - } catch (WrappedCommandException e) { + } catch (UsageException e) { + String message = e.getMessage(); + actor.printError(message != null ? message : "The command was not used properly (no more help available)."); + } catch (CommandExecutionException e) { Throwable t = e.getCause(); actor.printError("Please report this error: [See console]"); actor.printRaw(t.getClass().getName() + ": " + t.getMessage()); @@ -343,9 +337,11 @@ public final class CommandManager { log.error("An unknown error occurred", e); } } finally { - EditSession editSession = locals.get(EditSession.class); + Optional editSessionOpt = commandManager.injectedValue(Key.get(EditSessionHolder.class)) + .map(EditSessionHolder::getSession); - if (editSession != null) { + if (editSessionOpt.isPresent()) { + EditSession editSession = editSessionOpt.get(); session.remember(editSession); editSession.flushSession(); @@ -373,22 +369,21 @@ public final class CommandManager { @Subscribe public void handleCommandSuggestion(CommandSuggestionEvent event) { try { - CommandLocals locals = new CommandLocals(); - locals.put(Actor.class, event.getActor()); - locals.put("arguments", event.getArguments()); - event.setSuggestions(dispatcher.getSuggestions(event.getArguments(), locals)); + commandManager.injectValue(Key.get(Actor.class), ValueProvider.constant(event.getActor())); + commandManager.injectValue(Key.get(Arguments.class), ValueProvider.constant(event::getArguments)); + // TODO suggestions } catch (CommandException e) { event.getActor().printError(e.getMessage()); } } /** - * Get the command dispatcher instance. + * Get the command manager instance. * - * @return the command dispatcher + * @return the command manager */ - public Dispatcher getDispatcher() { - return dispatcher; + public CommandManager getCommandManager() { + return commandManager; } public static java.util.logging.Logger getLogger() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index 3b8347e7d..692c1558e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -68,7 +68,7 @@ public class PlatformManager { private static final Logger logger = LoggerFactory.getLogger(PlatformManager.class); private final WorldEdit worldEdit; - private final CommandManager commandManager; + private final PlatformCommandMananger platformCommandMananger; private final List platforms = new ArrayList<>(); private final Map preferences = new EnumMap<>(Capability.class); private @Nullable String firstSeenVersion; @@ -83,7 +83,7 @@ public class PlatformManager { public PlatformManager(WorldEdit worldEdit) { checkNotNull(worldEdit); this.worldEdit = worldEdit; - this.commandManager = new CommandManager(worldEdit, this); + this.platformCommandMananger = new PlatformCommandMananger(worldEdit, this); // Register this instance for events worldEdit.getEventBus().register(this); @@ -277,8 +277,8 @@ public class PlatformManager { * * @return the command manager */ - public CommandManager getCommandManager() { - return commandManager; + public PlatformCommandMananger getPlatformCommandMananger() { + return platformCommandMananger; } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java index 10ba092a3..f8fa06ff6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java @@ -19,8 +19,7 @@ package com.sk89q.worldedit.internal.command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; +import com.google.inject.Key; import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; @@ -28,22 +27,22 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.util.command.parametric.AbstractInvokeListener; -import com.sk89q.worldedit.util.command.parametric.InvokeHandler; -import com.sk89q.worldedit.util.command.parametric.ParameterData; -import com.sk89q.worldedit.util.command.parametric.ParameterException; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.gen.CommandCallListener; -import java.io.Closeable; import java.lang.reflect.Method; +import java.util.Optional; import java.util.logging.Handler; import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkNotNull; /** * Logs called commands to a logger. */ -public class CommandLoggingHandler extends AbstractInvokeListener implements InvokeHandler, Closeable { +public class CommandLoggingHandler implements CommandCallListener, AutoCloseable { private final WorldEdit worldEdit; private final Logger logger; @@ -62,93 +61,77 @@ public class CommandLoggingHandler extends AbstractInvokeListener implements Inv } @Override - public void preProcess(Object object, Method method, ParameterData[] parameters, CommandContext context) throws CommandException, ParameterException { - } - - @Override - public void preInvoke(Object object, Method method, ParameterData[] parameters, Object[] args, CommandContext context) throws CommandException { + public void beforeCall(Method method, CommandParameters parameters) { Logging loggingAnnotation = method.getAnnotation(Logging.class); Logging.LogMode logMode; StringBuilder builder = new StringBuilder(); - + if (loggingAnnotation == null) { logMode = null; } else { logMode = loggingAnnotation.value(); } - Actor sender = context.getLocals().get(Actor.class); - Player player; + Optional playerOpt = parameters.injectedValue(Key.get(Actor.class)) + .filter(Player.class::isInstance) + .map(Player.class::cast); - if (sender == null) { + if (!playerOpt.isPresent()) { return; } - if (sender instanceof Player) { - player = (Player) sender; - } else { - return; - } + Player player = playerOpt.get(); - builder.append("WorldEdit: ").append(sender.getName()); - if (sender.isPlayer()) { - builder.append(" (in \"").append(player.getWorld().getName()).append("\")"); - } + builder.append("WorldEdit: ").append(player.getName()); + builder.append(" (in \"").append(player.getWorld().getName()).append("\")"); - builder.append(": ").append(context.getCommand()); - - if (context.argsLength() > 0) { - builder.append(" ").append(context.getJoinedStrings(0)); - } - - if (logMode != null && sender.isPlayer()) { + builder.append(": ").append(parameters.getMetadata().getCalledName()); + + builder.append(": ") + .append(Stream.concat( + Stream.of(parameters.getMetadata().getCalledName()), + parameters.getMetadata().getArguments().stream() + ).collect(Collectors.joining(" "))); + + if (logMode != null) { Vector3 position = player.getLocation().toVector(); LocalSession session = worldEdit.getSessionManager().get(player); - + switch (logMode) { - case PLACEMENT: - try { - position = session.getPlacementPosition(player).toVector3(); - } catch (IncompleteRegionException e) { + case PLACEMENT: + try { + position = session.getPlacementPosition(player).toVector3(); + } catch (IncompleteRegionException e) { + break; + } + /* FALL-THROUGH */ + + case POSITION: + builder.append(" - Position: ").append(position); break; - } - /* FALL-THROUGH */ - case POSITION: - builder.append(" - Position: ").append(position); - break; + case ALL: + builder.append(" - Position: ").append(position); + /* FALL-THROUGH */ - case ALL: - builder.append(" - Position: ").append(position); - /* FALL-THROUGH */ + case ORIENTATION_REGION: + builder.append(" - Orientation: ").append(player.getCardinalDirection().name()); + /* FALL-THROUGH */ - case ORIENTATION_REGION: - builder.append(" - Orientation: ").append(player.getCardinalDirection().name()); - /* FALL-THROUGH */ - - case REGION: - try { - builder.append(" - Region: ") + case REGION: + try { + builder.append(" - Region: ") .append(session.getSelection(player.getWorld())); - } catch (IncompleteRegionException e) { + } catch (IncompleteRegionException e) { + break; + } break; - } - break; } } logger.info(builder.toString()); } - @Override - public void postInvoke(Object object, Method method, ParameterData[] parameters, Object[] args, CommandContext context) throws CommandException { - } - - @Override - public InvokeHandler createInvokeHandler() { - return this; - } - @Override public void close() { for (Handler h : logger.getHandlers()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java index 10294c0a2..2e9c6fa62 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.internal.command; import static com.google.common.base.Preconditions.checkNotNull; -import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.worldedit.DisallowedItemException; import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.IncompleteRegionException; @@ -35,6 +34,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.InsufficientArgumentsException; import com.sk89q.worldedit.command.tool.InvalidToolBindException; +import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.util.command.parametric.ExceptionConverterHelper; @@ -42,6 +42,8 @@ import com.sk89q.worldedit.util.command.parametric.ExceptionMatch; import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException; import com.sk89q.worldedit.util.io.file.FilenameResolutionException; import com.sk89q.worldedit.util.io.file.InvalidFilenameException; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.ConditionFailedException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -65,99 +67,106 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { if (matcher.matches()) { throw new CommandException("Number expected; string \"" + matcher.group(1) - + "\" given."); + + "\" given.", e, null); } else { - throw new CommandException("Number expected; string given."); + throw new CommandException("Number expected; string given.", e, null); } } @ExceptionMatch public void convert(IncompleteRegionException e) throws CommandException { - throw new CommandException("Make a region selection first."); + throw new CommandException("Make a region selection first.", e, null); } @ExceptionMatch public void convert(UnknownItemException e) throws CommandException { - throw new CommandException("Block name '" + e.getID() + "' was not recognized."); + throw new CommandException("Block name '" + e.getID() + "' was not recognized.", e, null); } @ExceptionMatch public void convert(InvalidItemException e) throws CommandException { - throw new CommandException(e.getMessage()); + throw new CommandException(e.getMessage(), e, null); } @ExceptionMatch public void convert(DisallowedItemException e) throws CommandException { throw new CommandException("Block '" + e.getID() - + "' not allowed (see WorldEdit configuration)."); + + "' not allowed (see WorldEdit configuration).", e, null); } @ExceptionMatch public void convert(MaxChangedBlocksException e) throws CommandException { throw new CommandException("Max blocks changed in an operation reached (" - + e.getBlockLimit() + ")."); + + e.getBlockLimit() + ").", e, null); } @ExceptionMatch public void convert(MaxBrushRadiusException e) throws CommandException { - throw new CommandException("Maximum brush radius (in configuration): " + worldEdit.getConfiguration().maxBrushRadius); + throw new CommandException("Maximum brush radius (in configuration): " + worldEdit.getConfiguration().maxBrushRadius, e, null); } @ExceptionMatch public void convert(MaxRadiusException e) throws CommandException { - throw new CommandException("Maximum radius (in configuration): " + worldEdit.getConfiguration().maxRadius); + throw new CommandException("Maximum radius (in configuration): " + worldEdit.getConfiguration().maxRadius, e, null); } @ExceptionMatch public void convert(UnknownDirectionException e) throws CommandException { - throw new CommandException("Unknown direction: " + e.getDirection()); + throw new CommandException("Unknown direction: " + e.getDirection(), e, null); } @ExceptionMatch public void convert(InsufficientArgumentsException e) throws CommandException { - throw new CommandException(e.getMessage()); + throw new CommandException(e.getMessage(), e, null); } @ExceptionMatch public void convert(RegionOperationException e) throws CommandException { - throw new CommandException(e.getMessage()); + throw new CommandException(e.getMessage(), e, null); } @ExceptionMatch public void convert(ExpressionException e) throws CommandException { - throw new CommandException(e.getMessage()); + throw new CommandException(e.getMessage(), e, null); } @ExceptionMatch public void convert(EmptyClipboardException e) throws CommandException { - throw new CommandException("Your clipboard is empty. Use //copy first."); + throw new CommandException("Your clipboard is empty. Use //copy first.", e, null); } @ExceptionMatch public void convert(InvalidFilenameException e) throws CommandException { throw new CommandException("Filename '" + e.getFilename() + "' invalid: " - + e.getMessage()); + + e.getMessage(), e, null); } @ExceptionMatch public void convert(FilenameResolutionException e) throws CommandException { throw new CommandException( - "File '" + e.getFilename() + "' resolution error: " + e.getMessage()); + "File '" + e.getFilename() + "' resolution error: " + e.getMessage(), e, null); } @ExceptionMatch public void convert(InvalidToolBindException e) throws CommandException { - throw new CommandException("Can't bind tool to " + e.getItemType().getName() + ": " + e.getMessage()); + throw new CommandException("Can't bind tool to " + e.getItemType().getName() + ": " + e.getMessage(), e, null); } @ExceptionMatch public void convert(FileSelectionAbortedException e) throws CommandException { - throw new CommandException("File selection aborted."); + throw new CommandException("File selection aborted.", e, null); } @ExceptionMatch public void convert(WorldEditException e) throws CommandException { - throw new CommandException(e.getMessage(), e); + throw new CommandException(e.getMessage(), e, null); + } + + @ExceptionMatch + public void convert(ConditionFailedException e) throws CommandException { + if (e.getCondition() instanceof PermissionCondition) { + throw new CommandException("You are not permitted to do that. Are you in the right mode?", e, null); + } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java index 1eb9491ca..3ab0dda59 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java @@ -19,8 +19,9 @@ package com.sk89q.worldedit.util.command.parametric; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.WrappedCommandException; + +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.CommandExecutionException; /** * Used to convert a recognized {@link Throwable} into an appropriate @@ -29,7 +30,7 @@ import com.sk89q.minecraft.util.commands.WrappedCommandException; *

Methods (when invoked by a {@link ParametricBuilder}-created command) may throw * relevant exceptions that are not caught by the command manager, but translate * into reasonable exceptions for an application. However, unknown exceptions are - * normally simply wrapped in a {@link WrappedCommandException} and bubbled up. Only + * normally simply wrapped in a {@link CommandExecutionException} and bubbled up. Only * normal {@link CommandException}s will be printed correctly, so a converter translates * one of these unknown exceptions into an appropriate {@link CommandException}.

* diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java index 5b2d9fd5d..f13557487 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java @@ -19,8 +19,9 @@ package com.sk89q.worldedit.util.command.parametric; -import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.WrappedCommandException; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.CommandExecutionException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -75,9 +76,9 @@ public abstract class ExceptionConverterHelper implements ExceptionConverter { if (e.getCause() instanceof CommandException) { throw (CommandException) e.getCause(); } - throw new WrappedCommandException(e); + throw new CommandExecutionException(e, null); } catch (IllegalArgumentException | IllegalAccessException e) { - throw new WrappedCommandException(e); + throw new CommandExecutionException(e, null); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index 00a16c24e..c7c5cf40d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -22,7 +22,7 @@ package com.sk89q.worldedit.util.formatting.component; import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.extension.platform.CommandManager; +import com.sk89q.worldedit.extension.platform.PlatformCommandMananger; import com.sk89q.worldedit.util.command.CommandCallable; import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.util.command.Description; @@ -72,7 +72,7 @@ public class CommandUsageBox extends StyledFragment { String prefix = !commandString.isEmpty() ? commandString + " " : ""; List list = new ArrayList<>(dispatcher.getCommands()); - list.sort(new PrimaryAliasComparator(CommandManager.COMMAND_CLEAN_PATTERN)); + list.sort(new PrimaryAliasComparator(PlatformCommandMananger.COMMAND_CLEAN_PATTERN)); for (CommandMapping mapping : list) { if (locals == null || mapping.getCallable().testPermission(locals)) { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java index daab12824..2f4c650b9 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java @@ -19,15 +19,17 @@ package com.sk89q.worldedit.forge; +import com.google.common.collect.ImmutableList; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.tree.LiteralCommandNode; -import com.sk89q.worldedit.util.command.CommandMapping; +import com.sk89q.worldedit.command.util.PermissionCondition; import net.minecraft.command.CommandSource; import net.minecraft.entity.player.EntityPlayerMP; +import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Stream; import static net.minecraft.command.Commands.literal; @@ -35,11 +37,14 @@ public final class CommandWrapper { private CommandWrapper() { } - public static void register(CommandDispatcher dispatcher, CommandMapping command) { - for (String alias : command.getAllAliases()) { + public static void register(CommandDispatcher dispatcher, org.enginehub.piston.Command command) { + ImmutableList.Builder aliases = ImmutableList.builder(); + aliases.add(command.getName()).addAll(command.getAliases()); + for (String alias : aliases.build()) { LiteralArgumentBuilder base = literal(alias) .executes(FAKE_COMMAND); - if (command.getDescription().getPermissions().size() > 0) { + if (command.getCondition().as(PermissionCondition.class) + .filter(p -> p.getPermissions().size() > 0).isPresent()) { base.requires(requirementsFor(command)); } dispatcher.register(base); @@ -54,11 +59,14 @@ public final class CommandWrapper { return 1; }; - private static Predicate requirementsFor(CommandMapping mapping) { + private static Predicate requirementsFor(org.enginehub.piston.Command mapping) { return ctx -> { ForgePermissionsProvider permsProvider = ForgeWorldEdit.inst.getPermissionsProvider(); return ctx.getEntity() instanceof EntityPlayerMP && - mapping.getDescription().getPermissions().stream() + mapping.getCondition().as(PermissionCondition.class) + .map(PermissionCondition::getPermissions) + .map(Set::stream) + .orElseGet(Stream::empty) .allMatch(perm -> permsProvider.hasPermission( (EntityPlayerMP) ctx.getEntity(), perm )); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 0530acc54..5989634bd 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -19,14 +19,13 @@ package com.sk89q.worldedit.forge; +import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.AbstractPlatform; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; -import com.sk89q.worldedit.util.command.CommandMapping; -import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; import net.minecraft.command.Commands; @@ -36,13 +35,19 @@ import net.minecraft.server.management.PlayerList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.WorldServer; import net.minecraftforge.fml.server.ServerLifecycleHooks; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.EnumMap; import java.util.List; import java.util.Map; +import java.util.Set; + +import static java.util.stream.Collectors.toList; class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { @@ -117,16 +122,17 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { } @Override - public void registerCommands(Dispatcher dispatcher) { + public void registerCommands(CommandManager manager) { if (server == null) return; Commands mcMan = server.getCommandManager(); - for (final CommandMapping command : dispatcher.getCommands()) { + for (Command command : manager.getAllCommands().collect(toList())) { CommandWrapper.register(mcMan.getDispatcher(), command); - if (command.getDescription().getPermissions().size() > 0) { - for (int i = 1; i < command.getDescription().getPermissions().size(); i++) { - ForgeWorldEdit.inst.getPermissionsProvider().registerPermission(command.getDescription().getPermissions().get(i)); - } + Set perms = command.getCondition().as(PermissionCondition.class) + .map(PermissionCondition::getPermissions) + .orElseGet(Collections::emptySet); + if (perms.size() > 0) { + perms.forEach(ForgeWorldEdit.inst.getPermissionsProvider()::registerPermission); } } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java index f94bd3b08..164f600d5 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java @@ -19,23 +19,29 @@ package com.sk89q.worldedit.sponge; -import com.sk89q.worldedit.util.command.CommandMapping; +import com.sk89q.worldedit.command.util.PermissionCondition; +import org.enginehub.piston.Command; import org.spongepowered.api.command.CommandCallable; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.text.Text; +import java.util.Collections; import java.util.Optional; +import java.util.Set; public abstract class CommandAdapter implements CommandCallable { - private CommandMapping command; + private Command command; - protected CommandAdapter(CommandMapping command) { + protected CommandAdapter(Command command) { this.command = command; } @Override public boolean testPermission(CommandSource source) { - for (String perm : command.getDescription().getPermissions()) { + Set permissions = command.getCondition().as(PermissionCondition.class) + .map(PermissionCondition::getPermissions) + .orElseGet(Collections::emptySet); + for (String perm : permissions) { if (!source.hasPermission(perm)) { return false; } @@ -45,8 +51,8 @@ public abstract class CommandAdapter implements CommandCallable { @Override public Optional getShortDescription(CommandSource source) { - String description = command.getDescription().getDescription(); - if (description != null && !description.isEmpty()) { + String description = command.getDescription(); + if (!description.isEmpty()) { return Optional.of(Text.of(description)); } return Optional.empty(); @@ -54,8 +60,8 @@ public abstract class CommandAdapter implements CommandCallable { @Override public Optional getHelp(CommandSource source) { - String help = command.getDescription().getHelp(); - if (help != null && !help.isEmpty()) { + String help = command.getFullHelp(); + if (!help.isEmpty()) { return Optional.of(Text.of(help)); } return Optional.empty(); @@ -63,6 +69,6 @@ public abstract class CommandAdapter implements CommandCallable { @Override public Text getUsage(CommandSource source) { - return Text.of(command.getDescription().getUsage()); + return Text.of(command.getUsage()); } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java index 774347645..29d2fad5a 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.sponge; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.CommandEvent; @@ -33,6 +34,8 @@ import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; @@ -50,6 +53,8 @@ import java.util.Optional; import javax.annotation.Nullable; +import static java.util.stream.Collectors.toList; + class SpongePlatform extends AbstractPlatform implements MultiUserPlatform { private final SpongeWorldEdit mod; @@ -122,24 +127,26 @@ class SpongePlatform extends AbstractPlatform implements MultiUserPlatform { } @Override - public void registerCommands(Dispatcher dispatcher) { - for (CommandMapping command : dispatcher.getCommands()) { + public void registerCommands(CommandManager manager) { + for (Command command : manager.getAllCommands().collect(toList())) { CommandAdapter adapter = new CommandAdapter(command) { @Override public CommandResult process(CommandSource source, String arguments) throws org.spongepowered.api.command.CommandException { - CommandEvent weEvent = new CommandEvent(SpongeWorldEdit.inst().wrapCommandSource(source), command.getPrimaryAlias() + " " + arguments); + CommandEvent weEvent = new CommandEvent(SpongeWorldEdit.inst().wrapCommandSource(source), command.getName() + " " + arguments); WorldEdit.getInstance().getEventBus().post(weEvent); return weEvent.isCancelled() ? CommandResult.success() : CommandResult.empty(); } @Override public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { - CommandSuggestionEvent weEvent = new CommandSuggestionEvent(SpongeWorldEdit.inst().wrapCommandSource(source), command.getPrimaryAlias() + " " + arguments); + CommandSuggestionEvent weEvent = new CommandSuggestionEvent(SpongeWorldEdit.inst().wrapCommandSource(source), command.getName() + " " + arguments); WorldEdit.getInstance().getEventBus().post(weEvent); return weEvent.getSuggestions(); } }; - Sponge.getCommandManager().register(SpongeWorldEdit.inst(), adapter, command.getAllAliases()); + ImmutableList.Builder aliases = ImmutableList.builder(); + aliases.add(command.getName()).addAll(command.getAliases()); + Sponge.getCommandManager().register(SpongeWorldEdit.inst(), adapter, aliases.build()); } } From 2b10128720972d7d5d1842629f4c8758368e4588 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Apr 2019 01:25:19 -0700 Subject: [PATCH 015/366] Restore Logging for setbiome --- .../main/java/com/sk89q/worldedit/command/BiomeCommands.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index a1df6dcb5..5830474a2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.command; +import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -53,6 +54,8 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; +import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; + /** * Implements biome-related commands such as "/biomelist". */ @@ -172,7 +175,7 @@ public class BiomeCommands { desc = "Sets the biome of the player's current block or region.", descFooter = "By default, uses all the blocks in your selection" ) -// @Logging(REGION) + @Logging(REGION) @CommandPermissions("worldedit.biome.set") public void setBiome(Player player, LocalSession session, EditSession editSession, BiomeType target, From e4d809143220acdb6d9112853e72012fa129381d Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Apr 2019 02:01:25 -0700 Subject: [PATCH 016/366] Convert part of the brush commands --- .../worldedit/command/BrushCommands.java | 171 +++++++++--------- .../command/util/CreatureButcher.java | 2 +- .../platform/PlatformCommandMananger.java | 25 ++- 3 files changed, 112 insertions(+), 86 deletions(-) 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 26fcf4d92..41da9f0f3 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 @@ -19,11 +19,6 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -37,6 +32,7 @@ import com.sk89q.worldedit.command.tool.brush.HollowCylinderBrush; import com.sk89q.worldedit.command.tool.brush.HollowSphereBrush; import com.sk89q.worldedit.command.tool.brush.SmoothBrush; import com.sk89q.worldedit.command.tool.brush.SphereBrush; +import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CreatureButcher; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -48,13 +44,18 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.util.HandSide; -import com.sk89q.worldedit.util.command.binding.Switch; -import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.world.block.BlockTypes; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; + +import static com.google.common.base.Preconditions.checkNotNull; /** * Commands to set brush shape. */ +@CommandContainer public class BrushCommands { private final WorldEdit worldEdit; @@ -70,19 +71,16 @@ public class BrushCommands { } @Command( - aliases = { "sphere", "s" }, - usage = " [radius]", - flags = "h", - desc = "Choose the sphere brush", - help = - "Chooses the sphere brush.\n" + - "The -h flag creates hollow spheres instead.", - min = 1, - max = 2 + name = "sphere", + aliases = { "s" }, + desc = "Choose the sphere brush" ) @CommandPermissions("worldedit.brush.sphere") public void sphereBrush(Player player, LocalSession session, Pattern fill, - @Optional("2") double radius, @Switch('h') boolean hollow) throws WorldEditException { + @Arg(desc = "The radius of the sphere", def = "2") + double radius, + @Switch(name = 'h', desc = "Create hollow spheres instead") + boolean hollow) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); @@ -99,19 +97,18 @@ public class BrushCommands { } @Command( - aliases = { "cylinder", "cyl", "c" }, - usage = " [radius] [height]", - flags = "h", - desc = "Choose the cylinder brush", - help = - "Chooses the cylinder brush.\n" + - "The -h flag creates hollow cylinders instead.", - min = 1, - max = 3 + name = "cylinder", + aliases = { "cyl", "c" }, + desc = "Choose the cylinder brush" ) @CommandPermissions("worldedit.brush.cylinder") public void cylinderBrush(Player player, LocalSession session, Pattern fill, - @Optional("2") double radius, @Optional("1") int height, @Switch('h') boolean hollow) throws WorldEditException { + @Arg(desc = "The radius of the cylinder", def = "2") + double radius, + @Arg(desc = "The height of the cylinder", def = "1") + int height, + @Switch(name = 'h', desc = "Create hollow cylinders instead") + boolean hollow) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(height); @@ -129,19 +126,16 @@ public class BrushCommands { } @Command( - aliases = { "clipboard", "copy" }, - usage = "", - flags = "ap", - desc = "Choose the clipboard brush", - help = - "Chooses the clipboard brush.\n" + - "The -a flag makes it not paste air.\n" + - "Without the -p flag, the paste will appear centered at the target location. " + - "With the flag, then the paste will appear relative to where you had " + - "stood relative to the copied area when you copied it." + name = "clipboard", + aliases = { "copy" }, + desc = "Choose the clipboard brush" ) @CommandPermissions("worldedit.brush.clipboard") - public void clipboardBrush(Player player, LocalSession session, @Switch('a') boolean ignoreAir, @Switch('p') boolean usingOrigin) throws WorldEditException { + public void clipboardBrush(Player player, LocalSession session, + @Switch(name = 'a', desc = "Don't paste air from the clipboard") + boolean ignoreAir, + @Switch(name = 'p', desc = "Paste using clipboard origin, instead of being centered at the target location") + boolean usingOrigin) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); Clipboard clipboard = holder.getClipboard(); @@ -158,18 +152,18 @@ public class BrushCommands { } @Command( - aliases = { "smooth" }, - usage = "[size] [iterations] [filter]", + name = "smooth", desc = "Choose the terrain softener brush", - help = - "Chooses the terrain softener brush. Optionally, specify a mask of blocks to be used for the heightmap.\n" + - "For example, '/brush smooth 2 4 grass_block,dirt,stone'.", - min = 0, - max = 3 + descFooter = "Example: '/brush smooth 2 4 grass_block,dirt,stone'" ) @CommandPermissions("worldedit.brush.smooth") public void smoothBrush(Player player, LocalSession session, - @Optional("2") double radius, @Optional("4") int iterations, @Optional Mask mask) throws WorldEditException { + @Arg(desc = "The radius to sample for softening", def = "2") + double radius, + @Arg(desc = "The number of iterations to perform", def = "4") + int iterations, + @Arg(desc = "The mask of blocks to use for the heightmap", def = "") + Mask mask) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); @@ -180,14 +174,14 @@ public class BrushCommands { } @Command( - aliases = { "ex", "extinguish" }, - usage = "[radius]", - desc = "Shortcut fire extinguisher brush", - min = 0, - max = 1 + name = "extinguish", + aliases = { "ex" }, + desc = "Shortcut fire extinguisher brush" ) @CommandPermissions("worldedit.brush.ex") - public void extinguishBrush(Player player, LocalSession session, @Optional("5") double radius) throws WorldEditException { + public void extinguishBrush(Player player, LocalSession session, + @Arg(desc = "The radius to extinguish", def = "5") + double radius) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); @@ -201,19 +195,16 @@ public class BrushCommands { } @Command( - aliases = { "gravity", "grav" }, - usage = "[radius]", - flags = "h", - desc = "Gravity brush", - help = - "This brush simulates the affect of gravity.\n" + - "The -h flag makes it affect blocks starting at the world's max y, " + - "instead of the clicked block's y + radius.", - min = 0, - max = 1 + name = "gravity", + aliases = { "grav" }, + desc = "Gravity brush, simulates the effect of gravity" ) @CommandPermissions("worldedit.brush.gravity") - public void gravityBrush(Player player, LocalSession session, @Optional("5") double radius, @Switch('h') boolean fromMaxY) throws WorldEditException { + public void gravityBrush(Player player, LocalSession session, + @Arg(desc = "The radius to apply gravity in", def = "5") + double radius, + @Switch(name = 'h', desc = "Affect blocks starting at max Y, rather than the target location Y + radius") + boolean fromMaxY) throws WorldEditException { worldEdit.checkMaxBrushRadius(radius); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); @@ -225,29 +216,34 @@ public class BrushCommands { } @Command( - aliases = { "butcher", "kill" }, - usage = "[radius]", - flags = "plangbtfr", - desc = "Butcher brush", - help = "Kills nearby mobs within the specified radius.\n" + - "Flags:\n" + - " -p also kills pets.\n" + - " -n also kills NPCs.\n" + - " -g also kills Golems.\n" + - " -a also kills animals.\n" + - " -b also kills ambient mobs.\n" + - " -t also kills mobs with name tags.\n" + - " -f compounds all previous flags.\n" + - " -r also destroys armor stands.\n" + - " -l currently does nothing.", - min = 0, - max = 1 + name = "butcher", + aliases = { "kill" }, + desc = "Butcher brush, kills mobs within a radius" ) @CommandPermissions("worldedit.brush.butcher") - public void butcherBrush(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void butcherBrush(Player player, LocalSession session, + @Arg(desc = "Radius to kill mobs in", def = "5") + double radius, + @Switch(name = 'p', desc = "Also kill pets") + boolean killPets, + @Switch(name = 'n', desc = "Also kill NPCs") + boolean killNpcs, + @Switch(name = 'g', desc = "Also kill golems") + boolean killGolems, + @Switch(name = 'a', desc = "Also kill animals") + boolean killAnimals, + @Switch(name = 'b', desc = "Also kill ambient mobs") + boolean killAmbient, + @Switch(name = 't', desc = "Also kill mobs with name tags") + boolean killWithName, + @Switch(name = 'f', desc = "Also kill all friendly mobs (Applies the flags `-abgnpt`)") + boolean killFriendly, + @Switch(name = 'r', desc = "Also destroy armor stands") + boolean killArmorStands, + @Switch(name = 'l', desc = "Kill via lightning. Currently non-functioning.") + boolean killWithLightning) throws WorldEditException { LocalConfiguration config = worldEdit.getConfiguration(); - double radius = args.argsLength() > 0 ? args.getDouble(0) : 5; double maxRadius = config.maxBrushRadius; // hmmmm not horribly worried about this because -1 is still rather efficient, // the problem arises when butcherMaxRadius is some really high number but not infinite @@ -261,7 +257,16 @@ public class BrushCommands { } CreatureButcher flags = new CreatureButcher(player); - flags.fromCommand(args); + flags.or(CreatureButcher.Flags.FRIENDLY , killFriendly); // No permission check here. Flags will instead be filtered by the subsequent calls. + flags.or(CreatureButcher.Flags.PETS , killPets, "worldedit.butcher.pets"); + flags.or(CreatureButcher.Flags.NPCS , killNpcs, "worldedit.butcher.npcs"); + flags.or(CreatureButcher.Flags.GOLEMS , killGolems, "worldedit.butcher.golems"); + flags.or(CreatureButcher.Flags.ANIMALS , killAnimals, "worldedit.butcher.animals"); + flags.or(CreatureButcher.Flags.AMBIENT , killAmbient, "worldedit.butcher.ambient"); + flags.or(CreatureButcher.Flags.TAGGED , killWithName, "worldedit.butcher.tagged"); + flags.or(CreatureButcher.Flags.ARMOR_STAND , killArmorStands, "worldedit.butcher.armorstands"); + + flags.or(CreatureButcher.Flags.WITH_LIGHTNING, killWithLightning, "worldedit.butcher.lightning"); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); tool.setSize(radius); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java index 94c7d5ad2..940d6a99c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java @@ -29,7 +29,7 @@ import com.sk89q.worldedit.function.EntityFunction; */ public class CreatureButcher { - final class Flags { + public final class Flags { @SuppressWarnings("PointlessBitwiseExpression") public static final int PETS = 1 << 0; public static final int NPCS = 1 << 1; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index e08c44eb5..5851efe9c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -30,6 +30,8 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.BiomeCommands; import com.sk89q.worldedit.command.BiomeCommandsRegistration; +import com.sk89q.worldedit.command.BrushCommands; +import com.sk89q.worldedit.command.BrushCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; @@ -145,7 +147,27 @@ public final class PlatformCommandMananger { cmd.addPart(SubCommandPart.builder("action", "Sub-command to run.") .withCommands(manager.getAllCommands().collect(Collectors.toList())) .required() - .build()); + .build()); + }); + + commandManager.register("brush", cmd -> { + cmd.aliases(ImmutableList.of("br")); + cmd.description("Brushing commands"); + cmd.action(Command.Action.NULL_ACTION); + + CommandManager manager = DefaultCommandManagerService.getInstance() + .newCommandManager(); + BrushCommandsRegistration.builder() + .commandManager(manager) + .containerInstance(new BrushCommands(worldEdit)) + .commandPermissionsConditionGenerator( + permsGenerator + ).build(); + + cmd.addPart(SubCommandPart.builder("action", "Sub-command to run.") + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() + .build()); }); BiomeCommandsRegistration.builder() @@ -183,7 +205,6 @@ public final class PlatformCommandMananger { .parent() .group("brush", "br") .describeAs("Brushing commands") - .registerMethods(new BrushCommands(worldEdit)) .register(adapt(new ShapedBrushCommand(new DeformCommand(), "worldedit.brush.deform")), "deform") .register(adapt(new ShapedBrushCommand(new ApplyCommand(new ReplaceParser(), "Set all blocks within region"), "worldedit.brush.set")), "set") .register(adapt(new ShapedBrushCommand(new PaintCommand(), "worldedit.brush.paint")), "paint") From e127bb89e56b670bc6629dca30807420256ed36d Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Apr 2019 02:03:05 -0700 Subject: [PATCH 017/366] Align annotation formatting with brush command methods --- .../worldedit/command/BiomeCommands.java | 16 +++++------ .../worldedit/command/SchematicCommands.java | 27 ++++++++++++------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index 5830474a2..81d208885 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -75,7 +75,8 @@ public class BiomeCommands { ) @CommandPermissions("worldedit.biome.list") public void biomeList(Player player, - @Arg(desc = "Page number.", def = "0") int page) throws WorldEditException { + @Arg(desc = "Page number.", def = "0") + int page) throws WorldEditException { int offset; int count = 0; @@ -115,12 +116,10 @@ public class BiomeCommands { ) @CommandPermissions("worldedit.biome.info") public void biomeInfo(Player player, LocalSession session, - @Switch( - name = 't', desc="Use the block you are looking at." - ) boolean useLineOfSight, - @Switch( - name = 'p', desc="Use the block you are currently in." - ) boolean usePosition) throws WorldEditException { + @Switch(name = 't', desc="Use the block you are looking at.") + boolean useLineOfSight, + @Switch(name = 'p', desc="Use the block you are currently in.") + boolean usePosition) throws WorldEditException { BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); Set biomes = new HashSet<>(); @@ -179,7 +178,8 @@ public class BiomeCommands { @CommandPermissions("worldedit.biome.set") public void setBiome(Player player, LocalSession session, EditSession editSession, BiomeType target, - @Switch(name = 'p', desc = "Use your current position") boolean atPosition) throws WorldEditException { + @Switch(name = 'p', desc = "Use your current position") + boolean atPosition) throws WorldEditException { World world = player.getWorld(); Region region; Mask mask = editSession.getMask(); 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 2bdd77bf0..ffa28d8ec 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 @@ -91,8 +91,10 @@ public class SchematicCommands { ) @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load"}) public void load(Player player, LocalSession session, - @Arg(desc = "File name.") String filename, - @Arg(desc = "Format name.", def = "sponge") String formatName) throws FilenameException { + @Arg(desc = "File name.") + String filename, + @Arg(desc = "Format name.", def = "sponge") + String formatName) throws FilenameException { LocalConfiguration config = worldEdit.getConfiguration(); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); @@ -134,9 +136,12 @@ public class SchematicCommands { ) @CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save"}) public void save(Player player, LocalSession session, - @Arg(desc = "File name.") String filename, - @Arg(desc = "Format name.", def = "sponge") String formatName, - @Switch(name = 'f', desc = "Overwrite an existing file.") boolean allowOverwrite + @Arg(desc = "File name.") + String filename, + @Arg(desc = "Format name.", def = "sponge") + String formatName, + @Switch(name = 'f', desc = "Overwrite an existing file.") + boolean allowOverwrite ) throws WorldEditException { LocalConfiguration config = worldEdit.getConfiguration(); @@ -205,7 +210,8 @@ public class SchematicCommands { ) @CommandPermissions("worldedit.schematic.delete") public void delete(Actor actor, - @Arg(desc = "File name.") String filename) throws WorldEditException { + @Arg(desc = "File name.") + String filename) throws WorldEditException { LocalConfiguration config = worldEdit.getConfiguration(); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); @@ -263,9 +269,12 @@ public class SchematicCommands { ) @CommandPermissions("worldedit.schematic.list") public void list(Actor actor, - @ArgFlag(name = 'p', desc = "Page to view.", def = "1") int page, - @Switch(name = 'd', desc = "Sort by date, oldest first") boolean oldFirst, - @Switch(name = 'n', desc = "Sort by date, newest first") boolean newFirst) { + @ArgFlag(name = 'p', desc = "Page to view.", def = "1") + int page, + @Switch(name = 'd', desc = "Sort by date, oldest first") + boolean oldFirst, + @Switch(name = 'n', desc = "Sort by date, newest first") + boolean newFirst) { if (oldFirst && newFirst) { throw new StopExecutionException("Cannot sort by oldest and newest."); } From 99da55dc944524536065f3fd5b1dc5bb5275dd72 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 15 Apr 2019 20:44:02 -0400 Subject: [PATCH 018/366] Fix building above bounds. --- .../src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 5dbdc09f6..152b1ac7d 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -428,7 +428,7 @@ public class ForgeWorld extends AbstractWorld { @Override public int getMaxY() { - return getWorld().getHeight(); + return getWorld().getHeight() - 1; } @Override From f33140b327c0137bc6e3a3073eca1df1e5e8a2bf Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 16 Apr 2019 23:02:23 -0700 Subject: [PATCH 019/366] Port ChunkCommands, fix up injection, simplify registration --- .../worldedit/command/BiomeCommands.java | 7 +- .../worldedit/command/BrushCommands.java | 3 +- .../worldedit/command/ChunkCommands.java | 35 ++--- .../worldedit/command/ClipboardCommands.java | 6 +- .../worldedit/command/GenerationCommands.java | 8 +- .../worldedit/command/NavigationCommands.java | 4 +- .../worldedit/command/RegionCommands.java | 9 +- .../worldedit/command/SchematicCommands.java | 3 +- .../worldedit/command/ScriptingCommands.java | 4 +- .../worldedit/command/SelectionCommands.java | 6 +- .../command/SnapshotUtilCommands.java | 4 +- .../worldedit/command/UtilityCommands.java | 14 +- .../worldedit/command/argument/Arguments.java | 3 +- .../CommandPermissionsConditionGenerator.java | 7 +- .../command/util}/Logging.java | 2 +- .../platform/PlatformCommandMananger.java | 122 ++++++++++++------ .../command/CommandLoggingHandler.java | 2 +- 17 files changed, 135 insertions(+), 104 deletions(-) rename worldedit-core/src/main/java/com/sk89q/{minecraft/util/commands => worldedit/command/util}/Logging.java (93%) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index 81d208885..0bf6878dd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -19,12 +19,13 @@ package com.sk89q.worldedit.command; -import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.function.FlatRegionFunction; @@ -54,12 +55,12 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; /** * Implements biome-related commands such as "/biomelist". */ -@CommandContainer +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class BiomeCommands { /** 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 41da9f0f3..e310f136a 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 @@ -33,6 +33,7 @@ import com.sk89q.worldedit.command.tool.brush.HollowSphereBrush; import com.sk89q.worldedit.command.tool.brush.SmoothBrush; import com.sk89q.worldedit.command.tool.brush.SphereBrush; import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CreatureButcher; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -55,7 +56,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Commands to set brush shape. */ -@CommandContainer +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class BrushCommands { private final WorldEdit worldEdit; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index 30d99269d..8f9dc6ceb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -20,22 +20,23 @@ package com.sk89q.worldedit.command; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; -import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.MathUtils; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.storage.LegacyChunkStore; import com.sk89q.worldedit.world.storage.McRegionChunkStore; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; import java.io.FileOutputStream; import java.io.IOException; @@ -45,21 +46,19 @@ import java.util.Set; /** * Commands for working with chunks. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class ChunkCommands { private final WorldEdit worldEdit; - + public ChunkCommands(WorldEdit worldEdit) { checkNotNull(worldEdit); this.worldEdit = worldEdit; } @Command( - aliases = { "chunkinfo" }, - usage = "", - desc = "Get information about the chunk that you are inside", - min = 0, - max = 0 + name = "chunkinfo", + desc = "Get information about the chunk that you are inside" ) @CommandPermissions("worldedit.chunkinfo") public void chunkInfo(Player player) throws WorldEditException { @@ -79,11 +78,8 @@ public class ChunkCommands { } @Command( - aliases = { "listchunks" }, - usage = "", - desc = "List chunks that your selection includes", - min = 0, - max = 0 + name = "listchunks", + desc = "List chunks that your selection includes" ) @CommandPermissions("worldedit.listchunks") public void listChunks(Player player, LocalSession session) throws WorldEditException { @@ -95,11 +91,8 @@ public class ChunkCommands { } @Command( - aliases = { "delchunks" }, - usage = "", - desc = "Delete chunks that your selection includes", - min = 0, - max = 0 + name = "delchunks", + desc = "Delete chunks that your selection includes" ) @CommandPermissions("worldedit.delchunks") @Logging(REGION) 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 0f61f0d2a..9d0dfe984 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 @@ -20,16 +20,16 @@ package com.sk89q.worldedit.command; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; 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 971fb58d8..f4578bdcd 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 @@ -20,17 +20,17 @@ package com.sk89q.worldedit.command; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; +import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; +import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.annotation.Selection; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java index 2d64d472b..b2fb9c4cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java @@ -20,15 +20,15 @@ package com.sk89q.worldedit.command; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.command.parametric.Optional; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index d788063d5..093d84f0e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -20,24 +20,23 @@ package com.sk89q.worldedit.command; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.ORIENTATION_REGION; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; +import static com.sk89q.worldedit.command.util.Logging.LogMode.ORIENTATION_REGION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; import static com.sk89q.worldedit.regions.Regions.asFlatRegion; import static com.sk89q.worldedit.regions.Regions.maximumBlockY; import static com.sk89q.worldedit.regions.Regions.minimumBlockY; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.generator.FloraGenerator; -import com.sk89q.worldedit.function.generator.ForestGenerator; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.NoiseFilter2D; 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 ffa28d8ec..5fd4c6d98 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 @@ -26,6 +26,7 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -65,7 +66,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Commands that work with schematic files. */ -@CommandContainer +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class SchematicCommands { /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java index 2b7d9a61f..d09c76c39 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java @@ -20,15 +20,15 @@ package com.sk89q.worldedit.command; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL; +import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import java.io.File; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 24e92070b..c79ec4fec 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -19,19 +19,19 @@ package com.sk89q.worldedit.command; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java index 51c5695e5..b8d6c7f3f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java @@ -22,12 +22,12 @@ package com.sk89q.worldedit.command; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.DataException; @@ -40,7 +40,7 @@ import com.sk89q.worldedit.world.storage.MissingWorldException; import java.io.File; import java.io.IOException; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; public class SnapshotUtilCommands { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 415b77adf..4d69452b2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -19,14 +19,12 @@ package com.sk89q.worldedit.command; -import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT; +import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; -import com.google.common.base.Joiner; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; @@ -34,12 +32,12 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CreatureButcher; import com.sk89q.worldedit.command.util.EntityRemover; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.extension.platform.PlatformCommandMananger; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.BlockPattern; @@ -53,17 +51,9 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CylinderRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.SessionOwner; -import com.sk89q.worldedit.util.command.CommandCallable; import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.util.command.Dispatcher; -import com.sk89q.worldedit.util.command.PrimaryAliasComparator; import com.sk89q.worldedit.util.command.binding.Text; -import com.sk89q.worldedit.util.formatting.ColorCodeBuilder; -import com.sk89q.worldedit.util.formatting.Style; -import com.sk89q.worldedit.util.formatting.StyledFragment; -import com.sk89q.worldedit.util.formatting.component.Code; -import com.sk89q.worldedit.util.formatting.component.CommandListBox; -import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java index 1bf5fc4e9..a1b444cbe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/Arguments.java @@ -19,7 +19,8 @@ package com.sk89q.worldedit.command.argument; -import org.enginehub.piston.InjectedValueAccess; + +import org.enginehub.piston.inject.InjectedValueAccess; /** * Key-interface for {@link InjectedValueAccess} for the String arguments. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java index 28041a1a1..b126198a6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java @@ -20,10 +20,9 @@ package com.sk89q.worldedit.command.util; import com.google.common.collect.ImmutableSet; -import com.google.inject.Key; -import com.sk89q.worldedit.extension.platform.Actor; import org.enginehub.piston.Command; import org.enginehub.piston.gen.CommandConditionGenerator; +import org.enginehub.piston.gen.CommandRegistration; import org.enginehub.piston.util.NonnullByDefault; import java.lang.reflect.Method; @@ -34,6 +33,10 @@ import static com.google.common.base.Preconditions.checkNotNull; @NonnullByDefault public class CommandPermissionsConditionGenerator implements CommandConditionGenerator { + public interface Registration { + Registration commandPermissionsConditionGenerator(CommandPermissionsConditionGenerator generator); + } + @Override public Command.Condition generateCondition(Method commandMethod) { CommandPermissions annotation = commandMethod.getAnnotation(CommandPermissions.class); diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Logging.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/Logging.java similarity index 93% rename from worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Logging.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/util/Logging.java index d8d87dcc0..e678cfde3 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/Logging.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/Logging.java @@ -20,7 +20,7 @@ //$Id$ -package com.sk89q.minecraft.util.commands; +package com.sk89q.worldedit.command.util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 5851efe9c..08c39fb49 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -21,9 +21,6 @@ package com.sk89q.worldedit.extension.platform; import com.google.common.collect.ImmutableList; import com.google.inject.Key; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.minecraft.util.commands.CommandPermissionsException; -import com.sk89q.minecraft.util.commands.WrappedCommandException; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; @@ -32,6 +29,8 @@ import com.sk89q.worldedit.command.BiomeCommands; import com.sk89q.worldedit.command.BiomeCommandsRegistration; import com.sk89q.worldedit.command.BrushCommands; import com.sk89q.worldedit.command.BrushCommandsRegistration; +import com.sk89q.worldedit.command.ChunkCommands; +import com.sk89q.worldedit.command.ChunkCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; @@ -44,18 +43,16 @@ import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.command.ActorAuthorizer; +import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import com.sk89q.worldedit.internal.command.UserCommandCompleter; import com.sk89q.worldedit.internal.command.WorldEditBinding; import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; +import com.sk89q.worldedit.session.SessionOwner; import com.sk89q.worldedit.session.request.Request; -import com.sk89q.worldedit.util.command.Dispatcher; -import com.sk89q.worldedit.util.command.InvalidUsageException; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.command.parametric.LegacyCommandsHandler; import com.sk89q.worldedit.util.command.parametric.ParametricBuilder; import com.sk89q.worldedit.util.eventbus.Subscribe; -import com.sk89q.worldedit.util.formatting.ColorCodeBuilder; -import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; import com.sk89q.worldedit.world.World; @@ -66,6 +63,12 @@ import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.CommandExecutionException; import org.enginehub.piston.exception.ConditionFailedException; import org.enginehub.piston.exception.UsageException; +import org.enginehub.piston.gen.CommandCallListener; +import org.enginehub.piston.gen.CommandRegistration; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.InjectedValueStore; +import org.enginehub.piston.inject.MapBackedValueStore; +import org.enginehub.piston.inject.MemoizingValueAccess; import org.enginehub.piston.part.SubCommandPart; import org.enginehub.piston.util.ValueProvider; import org.slf4j.Logger; @@ -73,6 +76,8 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; +import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.logging.FileHandler; import java.util.logging.Level; @@ -93,12 +98,14 @@ public final class PlatformCommandMananger { private static final java.util.logging.Logger commandLog = java.util.logging.Logger.getLogger(PlatformCommandMananger.class.getCanonicalName() + ".CommandLog"); private static final Pattern numberFormatExceptionPattern = Pattern.compile("^For input string: \"(.*)\"$"); + private static final CommandPermissionsConditionGenerator PERM_GEN = new CommandPermissionsConditionGenerator(); private final WorldEdit worldEdit; private final PlatformManager platformManager; private final CommandManager commandManager; private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler(); private final ExceptionConverter exceptionConverter; + private final List callListeners; /** * Create a new instance. @@ -113,7 +120,27 @@ public final class PlatformCommandMananger { this.exceptionConverter = new WorldEditExceptionConverter(worldEdit); this.commandManager = DefaultCommandManagerService.getInstance() .newCommandManager(); + this.callListeners = Collections.singletonList( + new CommandLoggingHandler(worldEdit, commandLog) + ); + // setup separate from main constructor + // ensures that everything is definitely assigned + initialize(); + } + private void register(CommandManager manager, CommandRegistration registration, CI instance) { + registration.containerInstance(instance) + .commandManager(manager) + .listeners(callListeners); + if (registration instanceof CommandPermissionsConditionGenerator.Registration) { + ((CommandPermissionsConditionGenerator.Registration) registration).commandPermissionsConditionGenerator( + PERM_GEN + ); + } + registration.build(); + } + + private void initialize() { // Register this instance for command events worldEdit.getEventBus().register(this); @@ -127,9 +154,6 @@ public final class PlatformCommandMananger { builder.addBinding(new WorldEditBinding(worldEdit)); builder.addInvokeListener(new LegacyCommandsHandler()); - CommandPermissionsConditionGenerator permsGenerator = - new CommandPermissionsConditionGenerator(); - commandManager.register("schematic", cmd -> { cmd.aliases(ImmutableList.of("schem", "/schematic", "/schem")); cmd.description("Schematic commands for saving/loading areas"); @@ -137,19 +161,17 @@ public final class PlatformCommandMananger { CommandManager manager = DefaultCommandManagerService.getInstance() .newCommandManager(); - SchematicCommandsRegistration.builder() - .commandManager(manager) - .containerInstance(new SchematicCommands(worldEdit)) - .commandPermissionsConditionGenerator( - permsGenerator - ).build(); + register( + manager, + SchematicCommandsRegistration.builder(), + new SchematicCommands(worldEdit) + ); cmd.addPart(SubCommandPart.builder("action", "Sub-command to run.") .withCommands(manager.getAllCommands().collect(Collectors.toList())) .required() .build()); }); - commandManager.register("brush", cmd -> { cmd.aliases(ImmutableList.of("br")); cmd.description("Brushing commands"); @@ -157,31 +179,33 @@ public final class PlatformCommandMananger { CommandManager manager = DefaultCommandManagerService.getInstance() .newCommandManager(); - BrushCommandsRegistration.builder() - .commandManager(manager) - .containerInstance(new BrushCommands(worldEdit)) - .commandPermissionsConditionGenerator( - permsGenerator - ).build(); + register( + manager, + BrushCommandsRegistration.builder(), + new BrushCommands(worldEdit) + ); cmd.addPart(SubCommandPart.builder("action", "Sub-command to run.") .withCommands(manager.getAllCommands().collect(Collectors.toList())) .required() .build()); }); - - BiomeCommandsRegistration.builder() - .commandManager(commandManager) - .containerInstance(new BiomeCommands()) - .commandPermissionsConditionGenerator(permsGenerator) - .build(); + register( + commandManager, + BiomeCommandsRegistration.builder(), + new BiomeCommands() + ); + register( + commandManager, + ChunkCommandsRegistration.builder(), + new ChunkCommands(worldEdit) + ); // Unported commands are below. Delete once they're added to the main manager above. /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new ChunkCommands(worldEdit)) .registerMethods(new ClipboardCommands(worldEdit)) .registerMethods(new GeneralCommands(worldEdit)) .registerMethods(new GenerationCommands(worldEdit)) @@ -309,13 +333,31 @@ public final class PlatformCommandMananger { } LocalConfiguration config = worldEdit.getConfiguration(); - commandManager.injectValue(Key.get(Actor.class), ValueProvider.constant(actor)); - commandManager.injectValue(Key.get(Arguments.class), ValueProvider.constant(event::getArguments)); - commandManager.injectValue(Key.get(EditSessionHolder.class), - context -> context.injectedValue(Key.get(Actor.class)) - .filter(Player.class::isInstance) - .map(Player.class::cast) - .map(p -> new EditSessionHolder(worldEdit, p))); + InjectedValueStore store = MapBackedValueStore.create(); + store.injectValue(Key.get(Actor.class), ValueProvider.constant(actor)); + if (actor instanceof Player) { + store.injectValue(Key.get(Player.class), ValueProvider.constant((Player) actor)); + } + store.injectValue(Key.get(Arguments.class), ValueProvider.constant(event::getArguments)); + store.injectValue(Key.get(LocalSession.class), + context -> { + LocalSession localSession = worldEdit.getSessionManager().get(actor); + localSession.tellVersion(actor); + return Optional.of(localSession); + }); + store.injectValue(Key.get(EditSession.class), + context -> { + LocalSession localSession = context.injectedValue(Key.get(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("No LocalSession")); + return context.injectedValue(Key.get(Player.class)) + .map(player -> { + EditSession editSession = localSession.createEditSession(player); + editSession.enableStandardMode(); + return editSession; + }); + }); + + MemoizingValueAccess context = MemoizingValueAccess.wrap(store); long start = System.currentTimeMillis(); @@ -325,7 +367,7 @@ public final class PlatformCommandMananger { // exceptions without writing a hook into every dispatcher, we need to unwrap these // exceptions and rethrow their converted form, if their is one. try { - commandManager.execute(ImmutableList.copyOf(split)); + commandManager.execute(context, ImmutableList.copyOf(split)); } catch (Throwable t) { // Use the exception converter to convert the exception if any of its causes // can be converted, otherwise throw the original exception @@ -358,8 +400,8 @@ public final class PlatformCommandMananger { log.error("An unknown error occurred", e); } } finally { - Optional editSessionOpt = commandManager.injectedValue(Key.get(EditSessionHolder.class)) - .map(EditSessionHolder::getSession); + Optional editSessionOpt = + context.injectedValueIfMemoized(Key.get(EditSession.class)); if (editSessionOpt.isPresent()) { EditSession editSession = editSessionOpt.get(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java index f8fa06ff6..8cd2cdb5f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java @@ -20,7 +20,7 @@ package com.sk89q.worldedit.internal.command; import com.google.inject.Key; -import com.sk89q.minecraft.util.commands.Logging; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; From 477e78bd17f3f6a12caffb2ac723f6a83e13584f Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 17 Apr 2019 00:15:05 -0700 Subject: [PATCH 020/366] [Forge] Update to latest forge for keyevent fixes --- worldedit-forge/build.gradle | 4 ++-- .../main/java/com/sk89q/worldedit/forge/KeyHandler.java | 6 ++---- .../java/com/sk89q/worldedit/forge/proxy/ServerProxy.java | 8 -------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 8fe3fb9af..8569d8506 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -14,7 +14,7 @@ buildscript { apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13.2" -def forgeVersion = "25.0.76" +def forgeVersion = "25.0.146" dependencies { compile project(':worldedit-core') @@ -29,7 +29,7 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 minecraft { - mappings channel: 'snapshot', version: '20190311-1.13.2' + mappings channel: 'snapshot', version: '20190415-1.13.2' runs { client = { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java index 06c59eb7f..bf18bd29f 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java @@ -22,9 +22,9 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.forge.gui.GuiReferenceCard; import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; +import net.minecraftforge.client.event.InputEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.registry.ClientRegistry; -import net.minecraftforge.fml.common.gameevent.InputEvent.KeyInputEvent; import org.lwjgl.glfw.GLFW; public class KeyHandler { @@ -37,11 +37,9 @@ public class KeyHandler { } @SubscribeEvent - public void onKey(KeyInputEvent evt) { + public void onKey(InputEvent.KeyInputEvent evt) { if (mc.player != null && mc.world != null && mainKey.isPressed()) { mc.displayGuiScreen(new GuiReferenceCard()); - // TODO Seems GuiHandlers don't work on client right now -// NetworkHooks.openGui(mc.player, new ResourceLocationInteractionObject(ServerProxy.REFERENCE_GUI)); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/proxy/ServerProxy.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/proxy/ServerProxy.java index 9ec84e328..a3375aa6f 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/proxy/ServerProxy.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/proxy/ServerProxy.java @@ -25,16 +25,8 @@ import net.minecraftforge.api.distmarker.OnlyIn; @OnlyIn(Dist.DEDICATED_SERVER) public class ServerProxy implements CommonProxy { -// public static ResourceLocation REFERENCE_GUI = new ResourceLocation("worldedit", "resource_gui"); - @Override public void registerHandlers() { -// ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.GUIFACTORY, () -> openContainer -> { -// if (openContainer.getId().equals(REFERENCE_GUI)) { -// return new GuiReferenceCard(); -// } -// return null; -// }); } } From 37c993be168ad41592458f0b70515533bdb4813a Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 18 Apr 2019 12:34:57 -0700 Subject: [PATCH 021/366] Port ClipboardCommands, update to new Key --- .../bukkit/BukkitCommandInspector.java | 4 +- .../worldedit/bukkit/WorldEditListener.java | 4 +- .../worldedit/command/ClipboardCommands.java | 145 ++++++++---------- .../command/util/PermissionCondition.java | 4 +- .../platform/PlatformCommandMananger.java | 33 ++-- .../internal/annotation/Selection.java | 4 +- .../command/CommandLoggingHandler.java | 6 +- 7 files changed, 93 insertions(+), 107 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java index 917d31981..d889903be 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java @@ -20,7 +20,6 @@ package com.sk89q.worldedit.bukkit; import com.google.common.collect.ImmutableMap; -import com.google.inject.Key; import com.sk89q.bukkit.util.CommandInspector; import com.sk89q.worldedit.extension.platform.Actor; import org.bukkit.command.Command; @@ -28,6 +27,7 @@ import org.bukkit.command.CommandSender; import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandParameters; import org.enginehub.piston.NoInputCommandParameters; +import org.enginehub.piston.inject.Key; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,7 +76,7 @@ class BukkitCommandInspector implements CommandInspector { if (mapping.isPresent()) { CommandParameters parameters = NoInputCommandParameters.builder() .injectedValues(ImmutableMap.of( - Key.get(Actor.class), plugin.wrapCommandSender(sender) + Key.of(Actor.class), plugin.wrapCommandSender(sender) )) .build(); return mapping.get().getCondition().satisfied(parameters); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java index 9c124f83f..9d335bb24 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.bukkit; import com.google.common.collect.ImmutableMap; -import com.google.inject.Key; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; @@ -43,6 +42,7 @@ import org.bukkit.inventory.EquipmentSlot; import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandParameters; import org.enginehub.piston.NoInputCommandParameters; +import org.enginehub.piston.inject.Key; /** * Handles all events thrown in relation to a Player @@ -110,7 +110,7 @@ public class WorldEditListener implements Listener { public void onPlayerCommand(PlayerCommandSendEvent event) { CommandParameters parameters = NoInputCommandParameters.builder() .injectedValues(ImmutableMap.of( - Key.get(Actor.class), plugin.wrapCommandSender(event.getPlayer()) + Key.of(Actor.class), plugin.wrapCommandSender(event.getPlayer()) )) .build(); CommandManager commandManager = plugin.getWorldEdit().getPlatformManager().getPlatformCommandMananger().getCommandManager(); 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 9d0dfe984..db5c5fa63 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 @@ -19,16 +19,11 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; -import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -48,42 +43,38 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.session.ClipboardHolder; -import com.sk89q.worldedit.util.command.binding.Switch; -import com.sk89q.worldedit.util.command.parametric.Optional; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.annotation.param.Switch; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; /** * Clipboard commands. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class ClipboardCommands { - private final WorldEdit worldEdit; - /** * Create a new instance. - * - * @param worldEdit reference to WorldEdit */ - public ClipboardCommands(WorldEdit worldEdit) { - checkNotNull(worldEdit); - this.worldEdit = worldEdit; + public ClipboardCommands() { } @Command( - aliases = { "/copy" }, - flags = "em", - desc = "Copy the selection to the clipboard", - help = "Copy the selection to the clipboard\n" + - "Flags:\n" + - " -e will also copy entities\n" + - " -m sets a source mask so that excluded blocks become air", - min = 0, - max = 0 + name = "/copy", + desc = "Copy the selection to the clipboard" ) @CommandPermissions("worldedit.clipboard.copy") public void copy(Player player, LocalSession session, EditSession editSession, - @Selection Region region, @Switch('e') boolean copyEntities, - @Switch('m') Mask mask) throws WorldEditException { - + @Selection Region region, + @Switch(name = 'e', desc = "Also copy entities") + boolean copyEntities, + @ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "") + Mask mask) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); @@ -98,22 +89,20 @@ public class ClipboardCommands { } @Command( - aliases = { "/cut" }, - flags = "em", - usage = "[leave-id]", + name = "/cut", desc = "Cut the selection to the clipboard", - help = "Copy the selection to the clipboard\n" + - "Flags:\n" + - " -e will also cut entities\n" + - " -m sets a source mask so that excluded blocks become air\n" + - "WARNING: Cutting and pasting entities cannot yet be undone!", - max = 1 + descFooter = "WARNING: Cutting and pasting entities cannot be undone!" ) @CommandPermissions("worldedit.clipboard.cut") @Logging(REGION) public void cut(Player player, LocalSession session, EditSession editSession, - @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities, - @Switch('m') Mask mask) throws WorldEditException { + @Selection Region region, + @Arg(desc = "Pattern to leave in place of the selection", def = "air") + Pattern leavePattern, + @Switch(name = 'e', desc = "Also cut entities") + boolean copyEntities, + @ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "") + Mask mask) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); clipboard.setOrigin(session.getPlacementPosition(player)); @@ -131,24 +120,18 @@ public class ClipboardCommands { } @Command( - aliases = { "/paste" }, - usage = "", - flags = "sao", - desc = "Paste the clipboard's contents", - help = - "Pastes the clipboard's contents.\n" + - "Flags:\n" + - " -a skips air blocks\n" + - " -o pastes at the original position\n" + - " -s selects the region after pasting", - min = 0, - max = 0 + name = "/paste", + desc = "Paste the clipboard's contents" ) @CommandPermissions("worldedit.clipboard.paste") @Logging(PLACEMENT) public void paste(Player player, LocalSession session, EditSession editSession, - @Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, - @Switch('s') boolean selectPasted) throws WorldEditException { + @Switch(name = 'a', desc = "Skip air blocks") + boolean ignoreAirBlocks, + @Switch(name = 'o', desc = "Paste at the original position") + boolean atOrigin, + @Switch(name = 's', desc = "Select the region after pasting") + boolean selectPasted) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); Clipboard clipboard = holder.getClipboard(); @@ -156,10 +139,10 @@ public class ClipboardCommands { BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player); Operation operation = holder - .createPaste(editSession) - .to(to) - .ignoreAirBlocks(ignoreAirBlocks) - .build(); + .createPaste(editSession) + .to(to) + .ignoreAirBlocks(ignoreAirBlocks) + .build(); Operations.completeLegacy(operation); if (selectPasted) { @@ -176,42 +159,43 @@ public class ClipboardCommands { } @Command( - aliases = { "/rotate" }, - usage = " [] []", + name = "/rotate", desc = "Rotate the contents of the clipboard", - help = "Non-destructively rotate the contents of the clipboard.\n" + - "Angles are provided in degrees and a positive angle will result in a clockwise rotation. " + - "Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n" + descFooter = "Non-destructively rotate the contents of the clipboard.\n" + + "Angles are provided in degrees and a positive angle will result in a clockwise rotation. " + + "Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n" ) @CommandPermissions("worldedit.clipboard.rotate") - public void rotate(Player player, LocalSession session, Double yRotate, @Optional Double xRotate, @Optional Double zRotate) throws WorldEditException { - if ((yRotate != null && Math.abs(yRotate % 90) > 0.001) || - xRotate != null && Math.abs(xRotate % 90) > 0.001 || - zRotate != null && Math.abs(zRotate % 90) > 0.001) { + public void rotate(Player player, LocalSession session, + @Arg(desc = "Amount to rotate on the y-axis") + double yRotate, + @Arg(desc = "Amount to rotate on the x-axis", def = "0") + double xRotate, + @Arg(desc = "Amount to rotate on the z-axis", def = "0") + double zRotate) throws WorldEditException { + if (Math.abs(yRotate % 90) > 0.001 || + Math.abs(xRotate % 90) > 0.001 || + Math.abs(zRotate % 90) > 0.001) { player.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended."); } ClipboardHolder holder = session.getClipboard(); AffineTransform transform = new AffineTransform(); - transform = transform.rotateY(-(yRotate != null ? yRotate : 0)); - transform = transform.rotateX(-(xRotate != null ? xRotate : 0)); - transform = transform.rotateZ(-(zRotate != null ? zRotate : 0)); + transform = transform.rotateY(-yRotate); + transform = transform.rotateX(-xRotate); + transform = transform.rotateZ(-zRotate); holder.setTransform(holder.getTransform().combine(transform)); player.print("The clipboard copy has been rotated."); } @Command( - aliases = { "/flip" }, - usage = "[]", - desc = "Flip the contents of the clipboard", - help = - "Flips the contents of the clipboard across the point from which the copy was made.\n", - min = 0, - max = 1 + name = "/flip", + desc = "Flip the contents of the clipboard across the origin" ) @CommandPermissions("worldedit.clipboard.flip") public void flip(Player player, LocalSession session, - @Optional(Direction.AIM) @Direction BlockVector3 direction) throws WorldEditException { + @Arg(desc = "The direction to flip, defaults to look direction.", def = Direction.AIM) + @Direction BlockVector3 direction) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); AffineTransform transform = new AffineTransform(); transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3()); @@ -220,11 +204,8 @@ public class ClipboardCommands { } @Command( - aliases = { "clearclipboard" }, - usage = "", - desc = "Clear your clipboard", - min = 0, - max = 0 + name = "clearclipboard", + desc = "Clear your clipboard" ) @CommandPermissions("worldedit.clipboard.clear") public void clearClipboard(Player player, LocalSession session) throws WorldEditException { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java index 2d7f7cd2e..4b33675f9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java @@ -19,16 +19,16 @@ package com.sk89q.worldedit.command.util; -import com.google.inject.Key; import com.sk89q.worldedit.extension.platform.Actor; import org.enginehub.piston.Command; import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.inject.Key; import java.util.Set; public final class PermissionCondition implements Command.Condition { - private static final Key ACTOR_KEY = Key.get(Actor.class); + private static final Key ACTOR_KEY = Key.of(Actor.class); private final Set permissions; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 08c39fb49..aefcb4323 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -20,7 +20,6 @@ package com.sk89q.worldedit.extension.platform; import com.google.common.collect.ImmutableList; -import com.google.inject.Key; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; @@ -31,10 +30,11 @@ import com.sk89q.worldedit.command.BrushCommands; import com.sk89q.worldedit.command.BrushCommandsRegistration; import com.sk89q.worldedit.command.ChunkCommands; import com.sk89q.worldedit.command.ChunkCommandsRegistration; +import com.sk89q.worldedit.command.ClipboardCommands; +import com.sk89q.worldedit.command.ClipboardCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; -import com.sk89q.worldedit.command.argument.EditSessionHolder; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Entity; @@ -47,7 +47,6 @@ import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import com.sk89q.worldedit.internal.command.UserCommandCompleter; import com.sk89q.worldedit.internal.command.WorldEditBinding; import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; -import com.sk89q.worldedit.session.SessionOwner; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.command.parametric.LegacyCommandsHandler; @@ -65,8 +64,8 @@ import org.enginehub.piston.exception.ConditionFailedException; import org.enginehub.piston.exception.UsageException; import org.enginehub.piston.gen.CommandCallListener; import org.enginehub.piston.gen.CommandRegistration; -import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueStore; +import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.MapBackedValueStore; import org.enginehub.piston.inject.MemoizingValueAccess; import org.enginehub.piston.part.SubCommandPart; @@ -200,13 +199,17 @@ public final class PlatformCommandMananger { ChunkCommandsRegistration.builder(), new ChunkCommands(worldEdit) ); + register( + commandManager, + ClipboardCommandsRegistration.builder(), + new ClipboardCommands() + ); // Unported commands are below. Delete once they're added to the main manager above. /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new ClipboardCommands(worldEdit)) .registerMethods(new GeneralCommands(worldEdit)) .registerMethods(new GenerationCommands(worldEdit)) .registerMethods(new HistoryCommands(worldEdit)) @@ -334,22 +337,22 @@ public final class PlatformCommandMananger { LocalConfiguration config = worldEdit.getConfiguration(); InjectedValueStore store = MapBackedValueStore.create(); - store.injectValue(Key.get(Actor.class), ValueProvider.constant(actor)); + store.injectValue(Key.of(Actor.class), ValueProvider.constant(actor)); if (actor instanceof Player) { - store.injectValue(Key.get(Player.class), ValueProvider.constant((Player) actor)); + store.injectValue(Key.of(Player.class), ValueProvider.constant((Player) actor)); } - store.injectValue(Key.get(Arguments.class), ValueProvider.constant(event::getArguments)); - store.injectValue(Key.get(LocalSession.class), + store.injectValue(Key.of(Arguments.class), ValueProvider.constant(event::getArguments)); + store.injectValue(Key.of(LocalSession.class), context -> { LocalSession localSession = worldEdit.getSessionManager().get(actor); localSession.tellVersion(actor); return Optional.of(localSession); }); - store.injectValue(Key.get(EditSession.class), + store.injectValue(Key.of(EditSession.class), context -> { - LocalSession localSession = context.injectedValue(Key.get(LocalSession.class)) + LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) .orElseThrow(() -> new IllegalStateException("No LocalSession")); - return context.injectedValue(Key.get(Player.class)) + return context.injectedValue(Key.of(Player.class)) .map(player -> { EditSession editSession = localSession.createEditSession(player); editSession.enableStandardMode(); @@ -401,7 +404,7 @@ public final class PlatformCommandMananger { } } finally { Optional editSessionOpt = - context.injectedValueIfMemoized(Key.get(EditSession.class)); + context.injectedValueIfMemoized(Key.of(EditSession.class)); if (editSessionOpt.isPresent()) { EditSession editSession = editSessionOpt.get(); @@ -432,8 +435,8 @@ public final class PlatformCommandMananger { @Subscribe public void handleCommandSuggestion(CommandSuggestionEvent event) { try { - commandManager.injectValue(Key.get(Actor.class), ValueProvider.constant(event.getActor())); - commandManager.injectValue(Key.get(Arguments.class), ValueProvider.constant(event::getArguments)); + commandManager.injectValue(Key.of(Actor.class), ValueProvider.constant(event.getActor())); + commandManager.injectValue(Key.of(Arguments.class), ValueProvider.constant(event::getArguments)); // TODO suggestions } catch (CommandException e) { event.getActor().printError(e.getMessage()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Selection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Selection.java index 9647c360f..1886f43f7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Selection.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Selection.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.internal.annotation; +import org.enginehub.piston.inject.InjectAnnotation; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -29,6 +31,6 @@ import java.lang.annotation.Target; */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) +@InjectAnnotation public @interface Selection { - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java index 8cd2cdb5f..f97123292 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java @@ -19,16 +19,16 @@ package com.sk89q.worldedit.internal.command; -import com.google.inject.Key; -import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.math.Vector3; import org.enginehub.piston.CommandParameters; import org.enginehub.piston.gen.CommandCallListener; +import org.enginehub.piston.inject.Key; import java.lang.reflect.Method; import java.util.Optional; @@ -72,7 +72,7 @@ public class CommandLoggingHandler implements CommandCallListener, AutoCloseable logMode = loggingAnnotation.value(); } - Optional playerOpt = parameters.injectedValue(Key.get(Actor.class)) + Optional playerOpt = parameters.injectedValue(Key.of(Actor.class)) .filter(Player.class::isInstance) .map(Player.class::cast); From ac03de89cc9b8be20fbf63b541360422f62ff462 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 18 Apr 2019 19:11:57 -0700 Subject: [PATCH 022/366] Work on adding converters for some arguments --- config/checkstyle/import-control.xml | 2 +- .../bukkit/BukkitCommandInspector.java | 10 +- .../worldedit/bukkit/WorldEditListener.java | 17 ++- worldedit-core/build.gradle | 3 + .../command/argument/DirectionConverter.java | 109 ++++++++++++++++++ .../command/argument/MaskConverter.java | 58 ++++++++++ .../command/argument/package-info.java | 21 ++++ .../platform/PlatformCommandMananger.java | 57 +++++++-- .../internal/annotation/Direction.java | 8 +- 9 files changed, 260 insertions(+), 25 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/package-info.java diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 5bcfffeb3..36ccf3d0b 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -17,7 +17,6 @@ - @@ -40,6 +39,7 @@ + diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java index d889903be..8944cb586 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java @@ -27,7 +27,10 @@ import org.bukkit.command.CommandSender; import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandParameters; import org.enginehub.piston.NoInputCommandParameters; +import org.enginehub.piston.inject.InjectedValueStore; import org.enginehub.piston.inject.Key; +import org.enginehub.piston.inject.MapBackedValueStore; +import org.enginehub.piston.inject.MemoizingValueAccess; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,10 +77,11 @@ class BukkitCommandInspector implements CommandInspector { public boolean testPermission(CommandSender sender, Command command) { Optional mapping = dispatcher.getCommand(command.getName()); if (mapping.isPresent()) { + InjectedValueStore store = MapBackedValueStore.create(); + store.injectValue(Key.of(Actor.class), context -> + Optional.of(plugin.wrapCommandSender(sender))); CommandParameters parameters = NoInputCommandParameters.builder() - .injectedValues(ImmutableMap.of( - Key.of(Actor.class), plugin.wrapCommandSender(sender) - )) + .injectedValues(MemoizingValueAccess.wrap(store)) .build(); return mapping.get().getCondition().satisfied(parameters); } else { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java index 9d335bb24..699263d50 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.bukkit; -import com.google.common.collect.ImmutableMap; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; @@ -42,7 +41,12 @@ import org.bukkit.inventory.EquipmentSlot; import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandParameters; import org.enginehub.piston.NoInputCommandParameters; +import org.enginehub.piston.inject.InjectedValueStore; import org.enginehub.piston.inject.Key; +import org.enginehub.piston.inject.MapBackedValueStore; +import org.enginehub.piston.inject.MemoizingValueAccess; + +import java.util.Optional; /** * Handles all events thrown in relation to a Player @@ -108,17 +112,18 @@ public class WorldEditListener implements Listener { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onPlayerCommand(PlayerCommandSendEvent event) { + InjectedValueStore store = MapBackedValueStore.create(); + store.injectValue(Key.of(Actor.class), context -> + Optional.of(plugin.wrapCommandSender(event.getPlayer()))); CommandParameters parameters = NoInputCommandParameters.builder() - .injectedValues(ImmutableMap.of( - Key.of(Actor.class), plugin.wrapCommandSender(event.getPlayer()) - )) + .injectedValues(MemoizingValueAccess.wrap(store)) .build(); CommandManager commandManager = plugin.getWorldEdit().getPlatformManager().getPlatformCommandMananger().getCommandManager(); event.getCommands().removeIf(name -> // remove if in the manager and not satisfied commandManager.getCommand(name) - .filter(command -> !command.getCondition().satisfied(parameters)) - .isPresent() + .filter(command -> !command.getCondition().satisfied(parameters)) + .isPresent() ); } diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index 23f96a592..efbf0aed3 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -33,6 +33,9 @@ dependencies { implementation "org.enginehub.piston.core-ap:runtime:$pistonVersion" annotationProcessor "org.enginehub.piston.core-ap:processor:$pistonVersion" api "org.enginehub.piston:default-impl:$pistonVersion" + def avVersion = "1.6.5" + compileOnly "com.google.auto.value:auto-value-annotations:$avVersion" + annotationProcessor "com.google.auto.value:auto-value:$avVersion" //compile 'net.sf.trove4j:trove4j:3.0.3' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java new file mode 100644 index 000000000..f454191da --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java @@ -0,0 +1,109 @@ +/* + * 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.command.argument; + +import com.google.auto.value.AutoAnnotation; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.UnknownDirectionException; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.math.BlockVector3; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; + +import static java.util.stream.Collectors.toList; + +public class DirectionConverter implements ArgumentConverter { + + @AutoAnnotation + private static Direction direction(boolean includeDiagonals) { + return new AutoAnnotation_DirectionConverter_direction(includeDiagonals); + } + + public static void register(WorldEdit worldEdit, CommandManager commandManager) { + commandManager.registerConverter( + Key.of(BlockVector3.class, direction(false)), + new DirectionConverter(worldEdit, false) + ); + commandManager.registerConverter( + Key.of(BlockVector3.class, direction(true)), + new DirectionConverter(worldEdit, true) + ); + } + + private static final ImmutableSet NON_DIAGONALS = ImmutableSet.of( + "north", "south", "east", "west", "up", "down" + ); + private static final ImmutableSet RELATIVE = ImmutableSet.of( + "me", "forward", "back", "left", "right" + ); + private static final ImmutableSet DIAGONALS = ImmutableSet.of( + "northeast", "northwest", "southeast", "southwest" + ); + + private final WorldEdit worldEdit; + private final boolean includeDiagonals; + private final ImmutableList suggestions; + + private DirectionConverter(WorldEdit worldEdit, boolean includeDiagonals) { + this.worldEdit = worldEdit; + this.includeDiagonals = includeDiagonals; + suggestions = ImmutableList.builder() + .addAll(NON_DIAGONALS) + .addAll(RELATIVE) + .addAll(includeDiagonals ? DIAGONALS : ImmutableList.of()) + .build(); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + Player player = context.injectedValue(Key.of(Player.class)) + .orElseThrow(() -> new IllegalStateException("No player available")); + try { + return SuccessfulConversion.fromSingle(includeDiagonals + ? worldEdit.getDiagonalDirection(player, argument) + : worldEdit.getDirection(player, argument)); + } catch (UnknownDirectionException e) { + return FailedConversion.from(e); + } + } + + @Override + public String describeAcceptableArguments() { + return "`me` to use facing direction, or any " + + (includeDiagonals ? "direction" : "non-diagonal direction"); + } + + @Override + public List getSuggestions(String input) { + return suggestions.stream() + .filter(s -> s.startsWith(input)) + .collect(toList()); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java new file mode 100644 index 000000000..cabe53ec5 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java @@ -0,0 +1,58 @@ +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.NoMatchException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.world.World; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +public class MaskConverter implements ArgumentConverter { + + public static void register(WorldEdit worldEdit, CommandManager commandManager) { + commandManager.registerConverter(Key.of(Mask.class), new MaskConverter(worldEdit)); + } + + private final WorldEdit worldEdit; + + private MaskConverter(WorldEdit worldEdit) { + this.worldEdit = worldEdit; + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + Actor actor = context.injectedValue(Key.of(Actor.class)) + .orElseThrow(() -> new IllegalStateException("No actor")); + ParserContext parserContext = new ParserContext(); + parserContext.setActor(actor); + if (actor instanceof Entity) { + Extent extent = ((Entity) actor).getExtent(); + if (extent instanceof World) { + parserContext.setWorld((World) extent); + } + } + parserContext.setSession(worldEdit.getSessionManager().get(actor)); + try { + return SuccessfulConversion.fromSingle( + worldEdit.getMaskFactory().parseFromInput(argument, parserContext) + ); + } catch (InputParseException e) { + return FailedConversion.from(e); + } + } + + @Override + public String describeAcceptableArguments() { + return "any mask"; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/package-info.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/package-info.java new file mode 100644 index 000000000..e1d68643b --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/package-info.java @@ -0,0 +1,21 @@ +/* + * 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 . + */ + +@org.enginehub.piston.util.NonnullByDefault +package com.sk89q.worldedit.command.argument; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index aefcb4323..7bbab6a16 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.extension.platform; import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -35,6 +36,8 @@ import com.sk89q.worldedit.command.ClipboardCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; +import com.sk89q.worldedit.command.argument.DirectionConverter; +import com.sk89q.worldedit.command.argument.MaskConverter; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Entity; @@ -42,11 +45,13 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.command.ActorAuthorizer; import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import com.sk89q.worldedit.internal.command.UserCommandCompleter; import com.sk89q.worldedit.internal.command.WorldEditBinding; import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.command.parametric.LegacyCommandsHandler; @@ -103,7 +108,7 @@ public final class PlatformCommandMananger { private final PlatformManager platformManager; private final CommandManager commandManager; private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler(); - private final ExceptionConverter exceptionConverter; + private final WorldEditExceptionConverter exceptionConverter; private final List callListeners; /** @@ -153,6 +158,45 @@ public final class PlatformCommandMananger { builder.addBinding(new WorldEditBinding(worldEdit)); builder.addInvokeListener(new LegacyCommandsHandler()); + registerAlwaysInjectedValues(); + registerArgumentConverters(); + registerAllCommands(); + } + + private void registerArgumentConverters() { + DirectionConverter.register(worldEdit, commandManager); + MaskConverter.register(worldEdit, commandManager); + } + + private void registerAlwaysInjectedValues() { + commandManager.injectValue(Key.of(Region.class, Selection.class), + context -> { + LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("No LocalSession")); + return context.injectedValue(Key.of(Player.class)) + .map(player -> { + try { + return localSession.getSelection(player.getWorld()); + } catch (IncompleteRegionException e) { + exceptionConverter.convert(e); + throw new AssertionError("Should have thrown a new exception."); + } + }); + }); + commandManager.injectValue(Key.of(EditSession.class), + context -> { + LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("No LocalSession")); + return context.injectedValue(Key.of(Player.class)) + .map(player -> { + EditSession editSession = localSession.createEditSession(player); + editSession.enableStandardMode(); + return editSession; + }); + }); + } + + private void registerAllCommands() { commandManager.register("schematic", cmd -> { cmd.aliases(ImmutableList.of("schem", "/schematic", "/schem")); cmd.description("Schematic commands for saving/loading areas"); @@ -348,17 +392,6 @@ public final class PlatformCommandMananger { localSession.tellVersion(actor); return Optional.of(localSession); }); - store.injectValue(Key.of(EditSession.class), - context -> { - LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) - .orElseThrow(() -> new IllegalStateException("No LocalSession")); - return context.injectedValue(Key.of(Player.class)) - .map(player -> { - EditSession editSession = localSession.createEditSession(player); - editSession.enableStandardMode(); - return editSession; - }); - }); MemoizingValueAccess context = MemoizingValueAccess.wrap(store); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Direction.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Direction.java index dbc7d3b29..bd2b55b4f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Direction.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Direction.java @@ -19,7 +19,8 @@ package com.sk89q.worldedit.internal.annotation; -import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.BlockVector3; +import org.enginehub.piston.inject.InjectAnnotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -27,12 +28,13 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Annotates a {@link Vector3} parameter to inject a direction. + * Annotates a {@link BlockVector3} parameter to inject a direction. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) +@InjectAnnotation public @interface Direction { - + String AIM = "me"; boolean includeDiagonals() default false; From 48fcfeed3573a81dd783d3664550d644b5e564f2 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 18 Apr 2019 19:12:09 -0700 Subject: [PATCH 023/366] Fix licenses --- .../command/argument/MaskConverter.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java index cabe53ec5..f53c5a180 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java @@ -1,3 +1,22 @@ +/* + * 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.command.argument; import com.sk89q.worldedit.WorldEdit; From f481f7d26da5f7f0c34bda85d0ec9b7ece3d343e Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 18 Apr 2019 19:59:53 -0700 Subject: [PATCH 024/366] Handle lack of global injected value store --- .../platform/PlatformCommandMananger.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 7bbab6a16..df71157f7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -73,6 +73,7 @@ import org.enginehub.piston.inject.InjectedValueStore; import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.MapBackedValueStore; import org.enginehub.piston.inject.MemoizingValueAccess; +import org.enginehub.piston.inject.MergedValueAccess; import org.enginehub.piston.part.SubCommandPart; import org.enginehub.piston.util.ValueProvider; import org.slf4j.Logger; @@ -107,6 +108,7 @@ public final class PlatformCommandMananger { private final WorldEdit worldEdit; private final PlatformManager platformManager; private final CommandManager commandManager; + private final InjectedValueStore globalInjectedValues; private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler(); private final WorldEditExceptionConverter exceptionConverter; private final List callListeners; @@ -124,6 +126,7 @@ public final class PlatformCommandMananger { this.exceptionConverter = new WorldEditExceptionConverter(worldEdit); this.commandManager = DefaultCommandManagerService.getInstance() .newCommandManager(); + this.globalInjectedValues = MapBackedValueStore.create(); this.callListeners = Collections.singletonList( new CommandLoggingHandler(worldEdit, commandLog) ); @@ -169,7 +172,7 @@ public final class PlatformCommandMananger { } private void registerAlwaysInjectedValues() { - commandManager.injectValue(Key.of(Region.class, Selection.class), + globalInjectedValues.injectValue(Key.of(Region.class, Selection.class), context -> { LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) .orElseThrow(() -> new IllegalStateException("No LocalSession")); @@ -183,7 +186,7 @@ public final class PlatformCommandMananger { } }); }); - commandManager.injectValue(Key.of(EditSession.class), + globalInjectedValues.injectValue(Key.of(EditSession.class), context -> { LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) .orElseThrow(() -> new IllegalStateException("No LocalSession")); @@ -393,7 +396,9 @@ public final class PlatformCommandMananger { return Optional.of(localSession); }); - MemoizingValueAccess context = MemoizingValueAccess.wrap(store); + MemoizingValueAccess context = MemoizingValueAccess.wrap( + MergedValueAccess.of(store, globalInjectedValues) + ); long start = System.currentTimeMillis(); @@ -437,7 +442,7 @@ public final class PlatformCommandMananger { } } finally { Optional editSessionOpt = - context.injectedValueIfMemoized(Key.of(EditSession.class)); + context.snapshotMemory().injectedValue(Key.of(EditSession.class)); if (editSessionOpt.isPresent()) { EditSession editSession = editSessionOpt.get(); @@ -468,8 +473,8 @@ public final class PlatformCommandMananger { @Subscribe public void handleCommandSuggestion(CommandSuggestionEvent event) { try { - commandManager.injectValue(Key.of(Actor.class), ValueProvider.constant(event.getActor())); - commandManager.injectValue(Key.of(Arguments.class), ValueProvider.constant(event::getArguments)); + globalInjectedValues.injectValue(Key.of(Actor.class), ValueProvider.constant(event.getActor())); + globalInjectedValues.injectValue(Key.of(Arguments.class), ValueProvider.constant(event::getArguments)); // TODO suggestions } catch (CommandException e) { event.getActor().printError(e.getMessage()); From 55348346e92a6ec548a70aed29084396f461054c Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Fri, 19 Apr 2019 14:49:29 +1000 Subject: [PATCH 025/366] Shade in Kashike's lib --- build.gradle | 3 +++ config/checkstyle/import-control.xml | 1 + worldedit-bukkit/build.gradle | 1 + .../com/sk89q/worldedit/bukkit/BukkitCommandSender.java | 8 ++++---- .../java/com/sk89q/worldedit/bukkit/BukkitPlayer.java | 9 ++++----- worldedit-core/build.gradle | 3 ++- .../com/sk89q/worldedit/extension/platform/Actor.java | 8 ++++---- .../sk89q/worldedit/extension/platform/PlayerProxy.java | 6 +++--- worldedit-forge/build.gradle | 1 + .../main/java/com/sk89q/worldedit/forge/ForgePlayer.java | 6 ++++++ worldedit-sponge/build.gradle | 1 + .../com/sk89q/worldedit/sponge/SpongeCommandSender.java | 7 +++++++ .../java/com/sk89q/worldedit/sponge/SpongePlayer.java | 7 +++++++ 13 files changed, 44 insertions(+), 17 deletions(-) diff --git a/build.gradle b/build.gradle index 8bdb1a122..57570e2ff 100644 --- a/build.gradle +++ b/build.gradle @@ -142,6 +142,9 @@ subprojects { include(dependency('com.sk89q:jchronic:0.2.4a')) include(dependency('com.thoughtworks.paranamer:paranamer:2.6')) include(dependency('com.sk89q.lib:jlibnoise:1.0.0')) + relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting') { + include(dependency('net.kyori:text-api:2.0.0')) + } } exclude 'GradleStart**' exclude '.cache' diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 28ccad1e4..b4a2f4808 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -16,6 +16,7 @@ + diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 335b96c0a..af7f00114 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -15,6 +15,7 @@ dependencies { compile 'org.bstats:bstats-bukkit:1.4' compile "io.papermc:paperlib:1.0.1" compile 'org.slf4j:slf4j-jdk14:1.7.26' + compile 'net.kyori:text-adapter-bukkit:1.0.3' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java index 7f48b193d..21d08d726 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java @@ -26,7 +26,8 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.auth.AuthorizationException; -import com.sk89q.worldedit.util.formatting.Fragment; +import net.kyori.text.TextComponent; +import net.kyori.text.adapter.bukkit.TextAdapter; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -93,9 +94,8 @@ public class BukkitCommandSender implements Actor { } @Override - public void print(Fragment fragment) { - // TODO Bukkit is bad and the API is somewhat lacking - printRaw(fragment.toString()); + public void print(TextComponent component) { + TextAdapter.sendComponent(sender, component); } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 8ef240f2c..ca15daa91 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -31,14 +31,14 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; -import com.sk89q.worldedit.util.formatting.Fragment; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; - +import net.kyori.text.TextComponent; +import net.kyori.text.adapter.bukkit.TextAdapter; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -127,9 +127,8 @@ public class BukkitPlayer extends AbstractPlayerActor { } @Override - public void print(Fragment fragment) { - // TODO Bukkit is bad and the API is somewhat lacking - printRaw(fragment.toString()); + public void print(TextComponent component) { + TextAdapter.sendComponent(player, component); } @Override diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index f91186083..e47c27f02 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -13,6 +13,7 @@ dependencies { compile 'com.sk89q.lib:jlibnoise:1.0.0' compile 'com.googlecode.json-simple:json-simple:1.1.1' compile 'org.slf4j:slf4j-api:1.7.26' + compile 'net.kyori:text-api:2.0.0' //compile 'net.sf.trove4j:trove4j:3.0.3' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } @@ -29,4 +30,4 @@ sourceSets { } } -build.dependsOn(shadowJar) +build.dependsOn(shadowJar { classifier = null }) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java index c5fb1b6b1..86bae5934 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java @@ -23,7 +23,7 @@ import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionOwner; import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.auth.Subject; -import com.sk89q.worldedit.util.formatting.Fragment; +import net.kyori.text.TextComponent; import java.io.File; @@ -77,11 +77,11 @@ public interface Actor extends Identifiable, SessionOwner, Subject { void printError(String msg); /** - * Print a {@link Fragment}. + * Print a {@link TextComponent}. * - * @param fragment The fragment to print + * @param component The component to print */ - void print(Fragment fragment); + void print(TextComponent component); /** * Returns true if the actor can destroy bedrock. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java index 54700aeea..5211e1380 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java @@ -31,10 +31,10 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.formatting.Fragment; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.gamemode.GameMode; +import net.kyori.text.TextComponent; import java.util.UUID; @@ -134,8 +134,8 @@ class PlayerProxy extends AbstractPlayerActor { } @Override - public void print(Fragment fragment) { - basePlayer.print(fragment); + public void print(TextComponent component) { + basePlayer.print(component); } @Override diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 8fe3fb9af..41c798310 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -19,6 +19,7 @@ def forgeVersion = "25.0.76" dependencies { compile project(':worldedit-core') compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.2' + compile 'net.kyori:text-serializer-gson:2.0.0' minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}" diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index 5b3b2ca84..57734f43a 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; +import net.kyori.text.TextComponent; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; @@ -141,6 +142,11 @@ public class ForgePlayer extends AbstractPlayerActor { sendColorized(msg, TextFormatting.RED); } + @Override + public void print(TextComponent component) { + // TODO + } + private void sendColorized(String msg, TextFormatting formatting) { for (String part : msg.split("\n")) { TextComponentString component = new TextComponentString(part); diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle index 0ef1e5361..f65952c91 100644 --- a/worldedit-sponge/build.gradle +++ b/worldedit-sponge/build.gradle @@ -19,6 +19,7 @@ dependencies { compile project(':worldedit-core') compile 'org.spongepowered:spongeapi:7.1.0' compile 'org.bstats:bstats-sponge:1.4' + compile 'net.kyori:text-adapter-spongeapi:1.0.3' testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1' } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java index bf1ceb7bd..fe5c626a3 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java @@ -26,6 +26,8 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.auth.AuthorizationException; +import net.kyori.text.TextComponent; +import net.kyori.text.adapter.spongeapi.TextAdapter; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; @@ -89,6 +91,11 @@ public class SpongeCommandSender implements Actor { sendColorized(msg, TextColors.RED); } + @Override + public void print(TextComponent component) { + TextAdapter.sendComponent(sender, component); + } + private void sendColorized(String msg, TextColor formatting) { for (String part : msg.split("\n")) { sender.sendMessage(Text.of(formatting, TextSerializers.LEGACY_FORMATTING_CODE.deserialize(part))); diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java index 3793ffb87..10b1f47e8 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java @@ -36,6 +36,8 @@ import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemTypes; +import net.kyori.text.TextComponent; +import net.kyori.text.adapter.spongeapi.TextAdapter; import org.spongepowered.api.Sponge; import org.spongepowered.api.data.type.HandTypes; import org.spongepowered.api.entity.living.player.Player; @@ -149,6 +151,11 @@ public class SpongePlayer extends AbstractPlayerActor { sendColorized(msg, TextColors.RED); } + @Override + public void print(TextComponent component) { + TextAdapter.sendComponent(player, component); + } + private void sendColorized(String msg, TextColor formatting) { for (String part : msg.split("\n")) { this.player.sendMessage(Text.of(formatting, TextSerializers.FORMATTING_CODE.deserialize(part))); From d56cd962829b2a323ed05aad09bf145202d8403a Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Fri, 19 Apr 2019 16:38:33 +1000 Subject: [PATCH 026/366] Fixed builds --- build.gradle | 2 +- worldedit-core/build.gradle | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 57570e2ff..f31f5b6a8 100644 --- a/build.gradle +++ b/build.gradle @@ -142,7 +142,7 @@ subprojects { include(dependency('com.sk89q:jchronic:0.2.4a')) include(dependency('com.thoughtworks.paranamer:paranamer:2.6')) include(dependency('com.sk89q.lib:jlibnoise:1.0.0')) - relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting') { + relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting.text') { include(dependency('net.kyori:text-api:2.0.0')) } } diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index e47c27f02..a83565dfc 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -1,3 +1,5 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + apply plugin: 'eclipse' apply plugin: 'idea' @@ -30,4 +32,7 @@ sourceSets { } } -build.dependsOn(shadowJar { classifier = null }) +task jar(type: ShadowJar, overwrite: true) { + from sourceSets.main.output + configurations = [project.configurations.runtime] +} \ No newline at end of file From 5b1573a24ebff8d1e11ba3255336fdf4ba8af1db Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Fri, 19 Apr 2019 23:06:00 +1000 Subject: [PATCH 027/366] Replace the message system --- build.gradle | 8 +- worldedit-bukkit/build.gradle | 1 + worldedit-core/build.gradle | 2 + .../worldedit/command/SelectionCommands.java | 12 +- .../worldedit/command/UtilityCommands.java | 23 +- .../extension/platform/CommandManager.java | 3 +- .../util/formatting/ColorCodeBuilder.java | 274 --------------- .../worldedit/util/formatting/Fragment.java | 121 ------- .../worldedit/util/formatting/Style.java | 274 --------------- .../worldedit/util/formatting/StyleSet.java | 320 ------------------ .../util/formatting/StyledFragment.java | 121 ------- .../util/formatting/component/Code.java | 10 +- .../formatting/component/CommandListBox.java | 10 +- .../formatting/component/CommandUsageBox.java | 22 +- .../util/formatting/component/Error.java | 10 +- .../util/formatting/component/Label.java | 10 +- .../util/formatting/component/MessageBox.java | 29 +- .../util/formatting/component/Subtle.java | 10 +- worldedit-forge/build.gradle | 1 + worldedit-sponge/build.gradle | 1 + 20 files changed, 82 insertions(+), 1180 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/ColorCodeBuilder.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Fragment.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Style.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyleSet.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyledFragment.java diff --git a/build.gradle b/build.gradle index f31f5b6a8..090626cc5 100644 --- a/build.gradle +++ b/build.gradle @@ -142,9 +142,11 @@ subprojects { include(dependency('com.sk89q:jchronic:0.2.4a')) include(dependency('com.thoughtworks.paranamer:paranamer:2.6')) include(dependency('com.sk89q.lib:jlibnoise:1.0.0')) - relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting.text') { - include(dependency('net.kyori:text-api:2.0.0')) - } + include(dependency('net.kyori:text-api:2.0.0')) + include(dependency("net.kyori:text-serializer-gson:2.0.0")) + include(dependency("net.kyori:text-serializer-legacy:2.0.0")) + + relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting.text') } exclude 'GradleStart**' exclude '.cache' diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index af7f00114..67ca5e43b 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -43,6 +43,7 @@ shadowJar { include(dependency(':worldedit-core')) include(dependency('org.slf4j:slf4j-api')) include(dependency("org.slf4j:slf4j-jdk14")) + include(dependency("net.kyori:text-adapter-bukkit:1.0.3")) relocate ("org.bstats", "com.sk89q.worldedit.bukkit.bstats") { include(dependency("org.bstats:bstats-bukkit:1.4")) } diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index a83565dfc..9d8176407 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -16,6 +16,8 @@ dependencies { compile 'com.googlecode.json-simple:json-simple:1.1.1' compile 'org.slf4j:slf4j-api:1.7.26' compile 'net.kyori:text-api:2.0.0' + compile 'net.kyori:text-serializer-gson:2.0.0' + compile 'net.kyori:text-serializer-legacy:2.0.0' //compile 'net.sf.trove4j:trove4j:3.0.3' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 24e92070b..ee93e847c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -55,15 +55,14 @@ import com.sk89q.worldedit.regions.selector.SphereRegionSelector; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.formatting.ColorCodeBuilder; -import com.sk89q.worldedit.util.formatting.Style; -import com.sk89q.worldedit.util.formatting.StyledFragment; import com.sk89q.worldedit.util.formatting.component.CommandListBox; +import com.sk89q.worldedit.util.formatting.component.Subtle; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.storage.ChunkStore; +import net.kyori.text.Component; import java.util.ArrayList; import java.util.List; @@ -754,9 +753,8 @@ public class SelectionCommands { limit.ifPresent(integer -> player.print(integer + " points maximum.")); } else { CommandListBox box = new CommandListBox("Selection modes"); - StyledFragment contents = box.getContents(); - StyledFragment tip = contents.createFragment(Style.RED); - tip.append("Select one of the modes below:").newLine(); + Component contents = box.getContents(); + contents.append(new Subtle("Select one of the modes below:").append(Component.newline())); box.appendCommand("cuboid", "Select two corners of a cuboid"); box.appendCommand("extend", "Fast cuboid selection mode"); @@ -766,7 +764,7 @@ public class SelectionCommands { box.appendCommand("cyl", "Select a cylinder"); box.appendCommand("convex", "Select a convex polyhedral"); - player.printRaw(ColorCodeBuilder.asColorCodes(box)); + player.print(box); return; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 8768be6c8..e8ee6275f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -58,15 +58,16 @@ import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.PrimaryAliasComparator; import com.sk89q.worldedit.util.command.binding.Text; -import com.sk89q.worldedit.util.formatting.ColorCodeBuilder; -import com.sk89q.worldedit.util.formatting.Style; -import com.sk89q.worldedit.util.formatting.StyledFragment; import com.sk89q.worldedit.util.formatting.component.Code; import com.sk89q.worldedit.util.formatting.component.CommandListBox; import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; +import com.sk89q.worldedit.util.formatting.component.Error; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; import java.util.ArrayList; import java.util.List; @@ -669,17 +670,17 @@ public class UtilityCommands { // Box CommandListBox box = new CommandListBox(String.format("Help: page %d/%d ", page + 1, pageTotal)); - StyledFragment contents = box.getContents(); - StyledFragment tip = contents.createFragment(Style.GRAY); + Component contents = box.getContents(); + Component tip = contents.append(TextComponent.of("", TextColor.GRAY)); if (offset >= aliases.size()) { - tip.createFragment(Style.RED).append(String.format("There is no page %d (total number of pages is %d).", page + 1, pageTotal)).newLine(); + tip.append(new Error(String.format("There is no page %d (total number of pages is %d).", page + 1, pageTotal))).append(Component.newline()); } else { List list = aliases.subList(offset, Math.min(offset + perPage, aliases.size())); - tip.append("Type "); - tip.append(new Code().append("//help ").append(" []")); - tip.append(" for more information.").newLine(); + tip.append(TextComponent.of("Type ")); + tip.append(new Code("//help ").append(TextComponent.of(" []"))); + tip.append(TextComponent.of(" for more information.")).append(Component.newline()); // Add each command for (CommandMapping mapping : list) { @@ -696,10 +697,10 @@ public class UtilityCommands { } } - actor.printRaw(ColorCodeBuilder.asColorCodes(box)); + actor.print(box); } else { CommandUsageBox box = new CommandUsageBox(callable, Joiner.on(" ").join(visited)); - actor.printRaw(ColorCodeBuilder.asColorCodes(box)); + actor.print(box); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index a0be07b65..11257efdf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -77,7 +77,6 @@ import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.command.parametric.LegacyCommandsHandler; import com.sk89q.worldedit.util.command.parametric.ParametricBuilder; import com.sk89q.worldedit.util.eventbus.Subscribe; -import com.sk89q.worldedit.util.formatting.ColorCodeBuilder; import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; @@ -300,7 +299,7 @@ public final class CommandManager { actor.printError("You are not permitted to do that. Are you in the right mode?"); } catch (InvalidUsageException e) { if (e.isFullHelpSuggested()) { - actor.printRaw(ColorCodeBuilder.asColorCodes(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals))); + actor.print(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals)); String message = e.getMessage(); if (message != null) { actor.printError(message); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/ColorCodeBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/ColorCodeBuilder.java deleted file mode 100644 index 14e8ddbca..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/ColorCodeBuilder.java +++ /dev/null @@ -1,274 +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 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.util.formatting; - -import com.google.common.base.Joiner; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -public class ColorCodeBuilder { - - private static final ColorCodeBuilder instance = new ColorCodeBuilder(); - private static final Joiner newLineJoiner = Joiner.on("\n"); - public static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 47; - - /** - * Convert a message into color-coded text. - * - * @param message the message - * @return a list of lines - */ - public String[] build(StyledFragment message) { - StringBuilder builder = new StringBuilder(); - buildFragment(builder, message, message.getStyle(), new StyleSet()); - return builder.toString().split("\r?\n"); - } - - /** - * Build a fragment. - * - * @param builder the string builder - * @param message the message - * @param parentStyle the parent style - * @param lastStyle the last style - * @return the last style used - */ - private StyleSet buildFragment(StringBuilder builder, StyledFragment message, StyleSet parentStyle, StyleSet lastStyle) { - for (Fragment node : message.getChildren()) { - if (node instanceof StyledFragment) { - StyledFragment fragment = (StyledFragment) node; - lastStyle = buildFragment( - builder, fragment, - parentStyle.extend(message.getStyle()), lastStyle); - } else { - StyleSet style = parentStyle.extend(message.getStyle()); - builder.append(getAdditive(style, lastStyle)); - builder.append(node); - lastStyle = style; - } - } - - return lastStyle; - } - - /** - * Get the formatting codes. - * - * @param style the style - * @return the color codes - */ - public static String getFormattingCode(StyleSet style) { - StringBuilder builder = new StringBuilder(); - if (style.isBold()) { - builder.append(Style.BOLD); - } - if (style.isItalic()) { - builder.append(Style.ITALIC); - } - if (style.isUnderline()) { - builder.append(Style.UNDERLINE); - } - if (style.isStrikethrough()) { - builder.append(Style.STRIKETHROUGH); - } - if (style.isObfuscated()) { - builder.append(Style.OBFUSCATED); - } - return builder.toString(); - } - - /** - * Get the formatting and color codes. - * - * @param style the style - * @return the color codes - */ - public static String getCode(StyleSet style) { - StringBuilder builder = new StringBuilder(); - builder.append(getFormattingCode(style)); - if (style.getColor() != null) { - builder.append(style.getColor()); - } - return builder.toString(); - } - - /** - * Get the additional color codes needed to set the given style when the current - * style is the other given one. - * - * @param resetTo the style to reset to - * @param resetFrom the style to reset from - * @return the color codes - */ - public static String getAdditive(StyleSet resetTo, StyleSet resetFrom) { - if (!resetFrom.hasFormatting() && resetTo.hasFormatting()) { - StringBuilder builder = new StringBuilder(); - builder.append(getFormattingCode(resetTo)); - if (resetFrom.getColor() != resetTo.getColor()) { - builder.append(resetTo.getColor()); - } - return builder.toString(); - } else if (!resetFrom.hasEqualFormatting(resetTo) || - (resetFrom.getColor() != null && resetTo.getColor() == null)) { - // Have to set reset code and add back all the formatting codes - return Style.RESET + getCode(resetTo); - } else { - if (resetFrom.getColor() != resetTo.getColor()) { - return String.valueOf(resetTo.getColor()); - } - } - - return ""; - } - - /** - * Word wrap the given text and maintain color codes throughout lines. - * - *

This is borrowed from Bukkit.

- * - * @param rawString the raw string - * @param lineLength the maximum line length - * @return a list of lines - */ - private String[] wordWrap(String rawString, int lineLength) { - // A null string is a single line - if (rawString == null) { - return new String[] {""}; - } - - // A string shorter than the lineWidth is a single line - if (rawString.length() <= lineLength && !rawString.contains("\n")) { - return new String[] {rawString}; - } - - char[] rawChars = (rawString + ' ').toCharArray(); // add a trailing space to trigger pagination - StringBuilder word = new StringBuilder(); - StringBuilder line = new StringBuilder(); - List lines = new LinkedList<>(); - int lineColorChars = 0; - - for (int i = 0; i < rawChars.length; i++) { - char c = rawChars[i]; - - // skip chat color modifiers - if (c == Style.COLOR_CHAR) { - word.append(Style.getByChar(rawChars[i + 1])); - lineColorChars += 2; - i++; // Eat the next character as we have already processed it - continue; - } - - if (c == ' ' || c == '\n') { - if (line.length() == 0 && word.length() > lineLength) { // special case: extremely long word begins a line - String wordStr = word.toString(); - String transformed; - if ((transformed = transform(wordStr)) != null) { - line.append(transformed); - } else { - lines.addAll(Arrays.asList(word.toString().split("(?<=\\G.{" + lineLength + "})"))); - } - } else if (line.length() + word.length() - lineColorChars == lineLength) { // Line exactly the correct length...newline - line.append(' '); - line.append(word); - lines.add(line.toString()); - line = new StringBuilder(); - lineColorChars = 0; - } else if (line.length() + 1 + word.length() - lineColorChars > lineLength) { // Line too long...break the line - String wordStr = word.toString(); - String transformed; - if (word.length() > lineLength && (transformed = transform(wordStr)) != null) { - if (line.length() + 1 + transformed.length() - lineColorChars > lineLength) { - lines.add(line.toString()); - line = new StringBuilder(transformed); - lineColorChars = 0; - } else { - if (line.length() > 0) { - line.append(' '); - } - line.append(transformed); - } - } else { - for (String partialWord : wordStr.split("(?<=\\G.{" + lineLength + "})")) { - lines.add(line.toString()); - line = new StringBuilder(partialWord); - } - lineColorChars = 0; - } - } else { - if (line.length() > 0) { - line.append(' '); - } - line.append(word); - } - word = new StringBuilder(); - - if (c == '\n') { // Newline forces the line to flush - lines.add(line.toString()); - line = new StringBuilder(); - } - } else { - word.append(c); - } - } - - if(line.length() > 0) { // Only add the last line if there is anything to add - lines.add(line.toString()); - } - - // Iterate over the wrapped lines, applying the last color from one line to the beginning of the next - if (lines.get(0).isEmpty() || lines.get(0).charAt(0) != Style.COLOR_CHAR) { - lines.set(0, Style.WHITE + lines.get(0)); - } - for (int i = 1; i < lines.size(); i++) { - final String pLine = lines.get(i-1); - final String subLine = lines.get(i); - - char color = pLine.charAt(pLine.lastIndexOf(Style.COLOR_CHAR) + 1); - if (subLine.isEmpty() || subLine.charAt(0) != Style.COLOR_CHAR) { - lines.set(i, Style.getByChar(color) + subLine); - } - } - - return lines.toArray(new String[lines.size()]); - } - - /** - * Callback for transforming a word, such as a URL. - * - * @param word the word - * @return the transformed value, or null to do nothing - */ - protected String transform(String word) { - return null; - } - - /** - * Convert the given styled fragment into color codes. - * - * @param fragment the fragment - * @return color codes - */ - public static String asColorCodes(StyledFragment fragment) { - return newLineJoiner.join(instance.build(fragment)); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Fragment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Fragment.java deleted file mode 100644 index e49d7c678..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Fragment.java +++ /dev/null @@ -1,121 +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 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.util.formatting; - -import java.util.ArrayList; -import java.util.List; - -/** - * A fragment of text. - */ -public class Fragment { - - private final StringBuilder builder = new StringBuilder(); - private final List children = new ArrayList<>(); - private Fragment lastText; - - Fragment() { - } - - public List getChildren() { - return children; - } - - protected Fragment lastText() { - Fragment text; - if (!children.isEmpty()) { - text = children.get(children.size() - 1); - if (text == lastText) { - return text; - } - } - - text = new Fragment(); - this.lastText = text; - children.add(text); - return text; - } - - public Fragment append(Fragment fragment) { - children.add(fragment); - return this; - } - - public Fragment append(String str) { - builder.append(Style.stripColor(str)); - return this; - } - - public Fragment append(Object obj) { - append(String.valueOf(obj)); - return this; - } - - public Fragment append(StringBuffer sb) { - append(String.valueOf(sb)); - return this; - } - - public Fragment append(CharSequence s) { - append(String.valueOf(s)); - return this; - } - - public Fragment append(boolean b) { - append(String.valueOf(b)); - return this; - } - - public Fragment append(char c) { - append(String.valueOf(c)); - return this; - } - - public Fragment append(int i) { - append(String.valueOf(i)); - return this; - } - - public Fragment append(long lng) { - append(String.valueOf(lng)); - return this; - } - - public Fragment append(float f) { - append(String.valueOf(f)); - return this; - } - - public Fragment append(double d) { - append(String.valueOf(d)); - return this; - } - - public Fragment newLine() { - append("\n"); - return this; - } - - @Override - public String toString() { - return builder.toString(); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Style.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Style.java deleted file mode 100644 index d81774009..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/Style.java +++ /dev/null @@ -1,274 +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 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.util.formatting; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.collect.Maps; - -import java.util.Map; -import java.util.regex.Pattern; - -/** - * All supported color values for chat. - */ -public enum Style { - /** - * Represents black - */ - BLACK('0', 0x00), - /** - * Represents dark blue - */ - BLUE_DARK('1', 0x1), - /** - * Represents dark green - */ - GREEN_DARK('2', 0x2), - /** - * Represents dark blue (aqua) - */ - CYAN_DARK('3', 0x3), - /** - * Represents dark red - */ - RED_DARK('4', 0x4), - /** - * Represents dark purple - */ - PURPLE_DARK('5', 0x5), - /** - * Represents gold - */ - YELLOW_DARK('6', 0x6), - /** - * Represents gray - */ - GRAY('7', 0x7), - /** - * Represents dark gray - */ - GRAY_DARK('8', 0x8), - /** - * Represents blue - */ - BLUE('9', 0x9), - /** - * Represents green - */ - GREEN('a', 0xA), - /** - * Represents aqua - */ - CYAN('b', 0xB), - /** - * Represents red - */ - RED('c', 0xC), - /** - * Represents light purple - */ - PURPLE('d', 0xD), - /** - * Represents yellow - */ - YELLOW('e', 0xE), - /** - * Represents white - */ - WHITE('f', 0xF), - /** - * Represents magical characters that change around randomly - */ - OBFUSCATED('k', 0x10, true), - /** - * Makes the text bold. - */ - BOLD('l', 0x11, true), - /** - * Makes a line appear through the text. - */ - STRIKETHROUGH('m', 0x12, true), - /** - * Makes the text appear underlined. - */ - UNDERLINE('n', 0x13, true), - /** - * Makes the text italic. - */ - ITALIC('o', 0x14, true), - /** - * Resets all previous chat colors or formats. - */ - RESET('r', 0x15); - - /** - * The special character which prefixes all chat color codes. Use this if you need to dynamically - * convert color codes from your custom format. - */ - public static final char COLOR_CHAR = '\u00A7'; - private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + COLOR_CHAR + "[0-9A-FK-OR]"); - - private final int intCode; - private final char code; - private final boolean isFormat; - private final String toString; - private final static Map BY_ID = Maps.newHashMap(); - private final static Map BY_CHAR = Maps.newHashMap(); - - Style(char code, int intCode) { - this(code, intCode, false); - } - - Style(char code, int intCode, boolean isFormat) { - this.code = code; - this.intCode = intCode; - this.isFormat = isFormat; - this.toString = new String(new char[] {COLOR_CHAR, code}); - } - - /** - * Gets the char value associated with this color - * - * @return A char value of this color code - */ - public char getChar() { - return code; - } - - @Override - public String toString() { - return toString; - } - - /** - * Checks if this code is a format code as opposed to a color code. - * - * @return the if the code is a formatting code - */ - public boolean isFormat() { - return isFormat; - } - - /** - * Checks if this code is a color code as opposed to a format code. - * - * @return the if the code is a color - */ - public boolean isColor() { - return !isFormat && this != RESET; - } - - /** - * Gets the color represented by the specified color code - * - * @param code Code to check - * @return Associative Style with the given code, or null if it doesn't exist - */ - public static Style getByChar(char code) { - return BY_CHAR.get(code); - } - - /** - * Gets the color represented by the specified color code - * - * @param code Code to check - * @return Associative Style with the given code, or null if it doesn't exist - */ - public static Style getByChar(String code) { - checkNotNull(code); - checkArgument(!code.isEmpty(), "Code must have at least one character"); - - return BY_CHAR.get(code.charAt(0)); - } - - /** - * Strips the given message of all color codes - * - * @param input String to strip of color - * @return A copy of the input string, without any coloring - */ - public static String stripColor(final String input) { - if (input == null) { - return null; - } - - return STRIP_COLOR_PATTERN.matcher(input).replaceAll(""); - } - - /** - * Translates a string using an alternate color code character into a string that uses the internal - * ChatColor.COLOR_CODE color code character. The alternate color code character will only be replaced - * if it is immediately followed by 0-9, A-F, a-f, K-O, k-o, R or r. - * - * @param altColorChar The alternate color code character to replace. Ex: & - * @param textToTranslate Text containing the alternate color code character. - * @return Text containing the ChatColor.COLOR_CODE color code character. - */ - public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) { - char[] b = textToTranslate.toCharArray(); - for (int i = 0; i < b.length - 1; i++) { - if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i+1]) > -1) { - b[i] = Style.COLOR_CHAR; - b[i+1] = Character.toLowerCase(b[i+1]); - } - } - return new String(b); - } - - /** - * Gets the ChatColors used at the end of the given input string. - * - * @param input Input string to retrieve the colors from. - * @return Any remaining ChatColors to pass onto the next line. - */ - public static String getLastColors(String input) { - String result = ""; - int length = input.length(); - - // Search backwards from the end as it is faster - for (int index = length - 1; index > -1; index--) { - char section = input.charAt(index); - if (section == COLOR_CHAR && index < length - 1) { - char c = input.charAt(index + 1); - Style color = getByChar(c); - - if (color != null) { - result = color + result; - - // Once we find a color or reset we can stop searching - if (color.isColor() || color == RESET) { - break; - } - } - } - } - - return result; - } - - static { - for (Style color : values()) { - BY_ID.put(color.intCode, color); - BY_CHAR.put(color.code, color); - } - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyleSet.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyleSet.java deleted file mode 100644 index 2a1c0cf46..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyleSet.java +++ /dev/null @@ -1,320 +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 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.util.formatting; - -import java.util.Objects; - -/** - * Represents set of styles, such as color, bold, etc. - */ -public class StyleSet { - - private Boolean bold; - private Boolean italic; - private Boolean underline; - private Boolean strikethrough; - private Boolean obfuscated; - private String insertion; - private Style color; - - /** - * Create a new style set with no properties set. - */ - public StyleSet() { - } - - /** - * Create a new style set with the given styles. - * - *

{@link Style#RESET} will be ignored if provided.

- * - * @param styles a list of styles - */ - public StyleSet(Style... styles) { - for (Style style : styles) { - if (style.isColor()) { - color = style; - } else if (style == Style.BOLD) { - bold = true; - } else if (style == Style.ITALIC) { - italic = true; - } else if (style == Style.UNDERLINE) { - underline = true; - } else if (style == Style.STRIKETHROUGH) { - strikethrough = true; - } else if (style == Style.OBFUSCATED) { - obfuscated = true; - } - } - } - - /** - * Get whether this style set is bold. - * - * @return true, false, or null if unset - */ - public Boolean getBold() { - return bold; - } - - /** - * Get whether the text is bold. - * - * @return true if bold - */ - public boolean isBold() { - return getBold() != null && getBold(); - } - - /** - * Set whether the text is bold. - * - * @param bold true, false, or null to unset - */ - public void setBold(Boolean bold) { - this.bold = bold; - } - - /** - * Get whether this style set is italicized. - * - * @return true, false, or null if unset - */ - public Boolean getItalic() { - return italic; - } - - /** - * Get whether the text is italicized. - * - * @return true if italicized - */ - public boolean isItalic() { - return getItalic() != null && getItalic(); - } - - /** - * Set whether the text is italicized. - * - * @param italic false, or null to unset - */ - public void setItalic(Boolean italic) { - this.italic = italic; - } - - /** - * Get whether this style set is underlined. - * - * @return true, false, or null if unset - */ - public Boolean getUnderline() { - return underline; - } - - /** - * Get whether the text is underlined. - * - * @return true if underlined - */ - public boolean isUnderline() { - return getUnderline() != null && getUnderline(); - } - - /** - * Set whether the text is underline. - * - * @param underline false, or null to unset - */ - public void setUnderline(Boolean underline) { - this.underline = underline; - } - - /** - * Get whether this style set is stricken through. - * - * @return true, false, or null if unset - */ - public Boolean getStrikethrough() { - return strikethrough; - } - - /** - * Get whether the text is stricken through. - * - * @return true if there is strikethrough applied - */ - public boolean isStrikethrough() { - return getStrikethrough() != null && getStrikethrough(); - } - - /** - * Set whether the text is stricken through. - * - * @param strikethrough false, or null to unset - */ - public void setStrikethrough(Boolean strikethrough) { - this.strikethrough = strikethrough; - } - - /** - * Get whether this style set is obfuscated. - * - * @return true, false, or null if unset - */ - public Boolean getObfuscated() { - return obfuscated; - } - - /** - * Get whether this style set is obfuscated. - * - * @return true if there is obfuscation applied - */ - public boolean isObfuscated() { - return getObfuscated() != null && getObfuscated(); - } - - /** - * Set whether the text is obfuscated. - * - * @param obfuscated false, or null to unset - */ - public void setObfuscated(Boolean obfuscated) { - this.obfuscated = obfuscated; - } - - /** - * Get this style set's insertion, if present. - * - * @return the insertion, or null if unset - */ - public String getInsertion() { - return insertion; - } - - /** - * Get whether this style set has an insertion. - * - * @return true if there is an insertion - */ - public boolean hasInsertion() { - return insertion != null; - } - - /** - * Set the style set's insertion. - * - * @param insertion the insertion, or null to unset - */ - public void setInsertion(String insertion) { - this.insertion = insertion; - } - - /** - * Get the color of the text. - * - * @return true, false, or null if unset - */ - public Style getColor() { - return color; - } - - /** - * Set the color of the text. - * - * @param color the color - */ - public void setColor(Style color) { - this.color = color; - } - - /** - * Return whether text formatting (bold, italics, underline, strikethrough) is set. - * - * @return true if formatting is set - */ - public boolean hasFormatting() { - return getBold() != null || getItalic() != null - || getUnderline() != null || getStrikethrough() != null - || getObfuscated() != null || getInsertion() != null; - } - - /** - * Return where the text formatting of the given style set is different from - * that assigned to this one. - * - * @param other the other style set - * @return true if there is a difference - */ - public boolean hasEqualFormatting(StyleSet other) { - return getBold() == other.getBold() && getItalic() == other.getItalic() - && getUnderline() == other.getUnderline() && - getStrikethrough() == other.getStrikethrough() && - getObfuscated() == other.getObfuscated() && - Objects.equals(getInsertion(), other.getInsertion()); - } - - /** - * Create a new instance with styles inherited from this one but with new styles - * from the given style set. - * - * @param style the style set - * @return a new style set instance - */ - public StyleSet extend(StyleSet style) { - StyleSet newStyle = clone(); - if (style.getBold() != null) { - newStyle.setBold(style.getBold()); - } - if (style.getItalic() != null) { - newStyle.setItalic(style.getItalic()); - } - if (style.getUnderline() != null) { - newStyle.setUnderline(style.getUnderline()); - } - if (style.getStrikethrough() != null) { - newStyle.setStrikethrough(style.getStrikethrough()); - } - if (style.getObfuscated() != null) { - newStyle.setObfuscated(style.getObfuscated()); - } - if (style.getInsertion() != null) { - newStyle.setInsertion(style.getInsertion()); - } - if (style.getColor() != null) { - newStyle.setColor(style.getColor()); - } - return newStyle; - } - - @Override - public StyleSet clone() { - StyleSet style = new StyleSet(); - style.setBold(getBold()); - style.setItalic(getItalic()); - style.setUnderline(getUnderline()); - style.setStrikethrough(getStrikethrough()); - style.setObfuscated(getObfuscated()); - style.setInsertion(getInsertion()); - style.setColor(getColor()); - return style; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyledFragment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyledFragment.java deleted file mode 100644 index ec0578d47..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/StyledFragment.java +++ /dev/null @@ -1,121 +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 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.util.formatting; - -/** - * A fragment of text that can be styled. - */ -public class StyledFragment extends Fragment { - - private StyleSet style; - - public StyledFragment() { - style = new StyleSet(); - } - - public StyledFragment(StyleSet style) { - this.style = style; - } - - public StyledFragment(Style... styles) { - this.style = new StyleSet(styles); - } - - public StyleSet getStyle() { - return style; - } - - public void setStyles(StyleSet style) { - this.style = style; - } - - public StyledFragment createFragment(Style... styles) { - StyledFragment fragment = new StyledFragment(styles); - append(fragment); - return fragment; - } - - @Override - public StyledFragment append(String str) { - lastText().append(str); - return this; - } - - @Override - public StyledFragment append(Object obj) { - append(String.valueOf(obj)); - return this; - } - - @Override - public StyledFragment append(StringBuffer sb) { - append(String.valueOf(sb)); - return this; - } - - @Override - public StyledFragment append(CharSequence s) { - append(String.valueOf(s)); - return this; - } - - @Override - public StyledFragment append(boolean b) { - append(String.valueOf(b)); - return this; - } - - @Override - public StyledFragment append(char c) { - append(String.valueOf(c)); - return this; - } - - @Override - public StyledFragment append(int i) { - append(String.valueOf(i)); - return this; - } - - @Override - public StyledFragment append(long lng) { - append(String.valueOf(lng)); - return this; - } - - @Override - public StyledFragment append(float f) { - append(String.valueOf(f)); - return this; - } - - @Override - public StyledFragment append(double d) { - append(String.valueOf(d)); - return this; - } - - @Override - public StyledFragment newLine() { - append("\n"); - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java index 953d83fe3..ec9164c72 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java @@ -19,19 +19,19 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.Style; -import com.sk89q.worldedit.util.formatting.StyledFragment; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; /** * Represents a fragment representing a command that is to be typed. */ -public class Code extends StyledFragment { +public class Code extends TextComponent { /** * Create a new instance. */ - public Code() { - super(Style.CYAN); + public Code(String message) { + super(builder(message).color(TextColor.AQUA)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java index 145b6baca..2767ff920 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -19,7 +19,9 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.Style; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; public class CommandListBox extends MessageBox { @@ -36,10 +38,10 @@ public class CommandListBox extends MessageBox { public CommandListBox appendCommand(String alias, String description) { if (!first) { - getContents().newLine(); + getContents().append(Component.newline()); } - getContents().createFragment(Style.YELLOW_DARK).append(alias).append(": "); - getContents().append(description); + getContents().append(TextComponent.of(alias, TextColor.GOLD).append(TextComponent.of(": "))); + getContents().append(TextComponent.of(description)); first = false; return this; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index 00a16c24e..fb0cc5c60 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -28,7 +28,8 @@ import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.util.command.Description; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.PrimaryAliasComparator; -import com.sk89q.worldedit.util.formatting.StyledFragment; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; import java.util.ArrayList; import java.util.List; @@ -38,7 +39,7 @@ import javax.annotation.Nullable; /** * A box to describe usage of a command. */ -public class CommandUsageBox extends StyledFragment { +public class CommandUsageBox extends TextComponent { /** * Create a new usage box. @@ -58,6 +59,7 @@ public class CommandUsageBox extends StyledFragment { * @param locals list of locals to use */ public CommandUsageBox(CommandCallable command, String commandString, @Nullable CommandLocals locals) { + super(builder()); checkNotNull(command); checkNotNull(commandString); if (command instanceof Dispatcher) { @@ -85,23 +87,23 @@ public class CommandUsageBox extends StyledFragment { private void attachCommandUsage(Description description, String commandString) { MessageBox box = new MessageBox("Help for " + commandString); - StyledFragment contents = box.getContents(); + Component contents = box.getContents(); if (description.getUsage() != null) { - contents.append(new Label().append("Usage: ")); - contents.append(description.getUsage()); + contents.append(new Label("Usage: ")); + contents.append(TextComponent.of(description.getUsage())); } else { - contents.append(new Subtle().append("Usage information is not available.")); + contents.append(new Subtle("Usage information is not available.")); } - contents.newLine(); + contents.append(Component.newline()); if (description.getHelp() != null) { - contents.append(description.getHelp()); + contents.append(TextComponent.of(description.getHelp())); } else if (description.getDescription() != null) { - contents.append(description.getDescription()); + contents.append(TextComponent.of(description.getDescription())); } else { - contents.append(new Subtle().append("No further help is available.")); + contents.append(new Subtle("No further help is available.")); } append(box); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java index 056c99c18..5042a3804 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java @@ -19,19 +19,19 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.Style; -import com.sk89q.worldedit.util.formatting.StyledFragment; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; /** * Represents a fragment representing an error. */ -public class Error extends StyledFragment { +public class Error extends TextComponent { /** * Create a new instance. */ - public Error() { - super(Style.RED); + public Error(String message) { + super(builder(message).color(TextColor.RED)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java index 8a59732b0..bc0e46527 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java @@ -19,19 +19,19 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.Style; -import com.sk89q.worldedit.util.formatting.StyledFragment; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; /** * Represents a fragment representing a label. */ -public class Label extends StyledFragment { +public class Label extends TextComponent { /** * Create a new instance. */ - public Label() { - super(Style.YELLOW); + public Label(String message) { + super(builder(message).color(TextColor.YELLOW)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java index 086ce05e9..7b2dcc72e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java @@ -21,36 +21,39 @@ package com.sk89q.worldedit.util.formatting.component; import static com.google.common.base.Preconditions.checkNotNull; -import com.sk89q.worldedit.util.formatting.ColorCodeBuilder; -import com.sk89q.worldedit.util.formatting.Style; -import com.sk89q.worldedit.util.formatting.StyledFragment; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; /** * Makes for a box with a border above and below. */ -public class MessageBox extends StyledFragment { +public class MessageBox extends TextComponent { - private final StyledFragment contents = new StyledFragment(); + public static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 47; + + private final Component contents = Component.empty(); /** * Create a new box. */ public MessageBox(String title) { + super(builder()); checkNotNull(title); - int leftOver = ColorCodeBuilder.GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH - title.length() - 2; + int leftOver = GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH - title.length() - 2; int leftSide = (int) Math.floor(leftOver * 1.0/3); int rightSide = (int) Math.floor(leftOver * 2.0/3); if (leftSide > 0) { - createFragment(Style.YELLOW).append(createBorder(leftSide)); + append(TextComponent.of(createBorder(leftSide), TextColor.YELLOW)); } - append(" "); - append(title); - append(" "); + append(Component.space()); + append(TextComponent.of(title)); + append(Component.space()); if (rightSide > 0) { - createFragment(Style.YELLOW).append(createBorder(rightSide)); + append(TextComponent.of(createBorder(rightSide), TextColor.YELLOW)); } - newLine(); + append(Component.newline()); append(contents); } @@ -67,7 +70,7 @@ public class MessageBox extends StyledFragment { * * @return the contents */ - public StyledFragment getContents() { + public Component getContents() { return contents; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java index 34316c087..68600f0a3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java @@ -19,19 +19,19 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.Style; -import com.sk89q.worldedit.util.formatting.StyledFragment; +import net.kyori.text.TextComponent; +import net.kyori.text.format.TextColor; /** * Represents a subtle part of the message. */ -public class Subtle extends StyledFragment { +public class Subtle extends TextComponent { /** * Create a new instance. */ - public Subtle() { - super(Style.GRAY); + public Subtle(String message) { + super(builder(message).color(TextColor.GRAY)); } } diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 41c798310..c1ce166c1 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -91,6 +91,7 @@ shadowJar { include(dependency(':worldedit-core')) include(dependency('org.slf4j:slf4j-api')) include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + include(dependency("net.kyori:text-serializer-gson:2.0.0")) } } diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle index f65952c91..762557b6e 100644 --- a/worldedit-sponge/build.gradle +++ b/worldedit-sponge/build.gradle @@ -43,6 +43,7 @@ shadowJar { dependencies { include(dependency(':worldedit-core')) include(dependency('org.bstats:bstats-sponge:1.4')) + include(dependency("net.kyori:text-adapter-spongeapi:1.0.3")) } } From a9926328f11bc60dd8442cb844658c693d38db8a Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 20 Apr 2019 12:13:46 -0400 Subject: [PATCH 028/366] Stop trying to redo when history runs out. --- .../main/java/com/sk89q/worldedit/command/HistoryCommands.java | 1 + 1 file changed, 1 insertion(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index b960dfbe4..773916d59 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -110,6 +110,7 @@ public class HistoryCommands { worldEdit.flushBlockBag(player, redone); } else { player.printError("Nothing left to redo."); + break; } } } From 1e7b4fc835ac202dc3b0d4e8a44362b2251ed692 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 20 Apr 2019 23:11:39 -0700 Subject: [PATCH 029/366] Move shaded libraries to their own artifacts --- build.gradle | 44 ++++----- settings.gradle | 7 +- worldedit-bukkit/build.gradle | 3 +- .../worldedit/bukkit/BukkitCommandSender.java | 4 +- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 4 +- worldedit-core/build.gradle | 7 +- .../worldedit/command/SelectionCommands.java | 10 +- .../worldedit/command/UtilityCommands.java | 10 +- .../worldedit/extension/platform/Actor.java | 2 +- .../extension/platform/PlayerProxy.java | 2 +- .../util/formatting/component/Code.java | 4 +- .../formatting/component/CommandListBox.java | 6 +- .../formatting/component/CommandUsageBox.java | 4 +- .../util/formatting/component/Error.java | 4 +- .../util/formatting/component/Label.java | 4 +- .../util/formatting/component/MessageBox.java | 8 +- .../util/formatting/component/Subtle.java | 4 +- .../sk89q/worldedit/forge/ForgePlayer.java | 2 +- worldedit-libs/build.gradle | 97 +++++++++++++++++++ worldedit-sponge/build.gradle | 3 +- .../worldedit/sponge/SpongeCommandSender.java | 4 +- .../sk89q/worldedit/sponge/SpongePlayer.java | 4 +- 22 files changed, 165 insertions(+), 72 deletions(-) create mode 100644 worldedit-libs/build.gradle diff --git a/build.gradle b/build.gradle index 090626cc5..16fd983db 100644 --- a/build.gradle +++ b/build.gradle @@ -82,6 +82,14 @@ artifactory { artifactoryPublish.skip = true subprojects { + repositories { + mavenCentral() + maven { url "http://maven.sk89q.com/repo/" } + maven { url "http://repo.maven.apache.org/maven2" } + } +} + +configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) { apply plugin: 'java' apply plugin: 'maven' apply plugin: 'checkstyle' @@ -97,12 +105,6 @@ subprojects { checkstyle.configFile = new File(rootProject.projectDir, "config/checkstyle/checkstyle.xml") checkstyle.toolVersion = '7.6.1' - repositories { - mavenCentral() - maven { url "http://maven.sk89q.com/repo/" } - maven { url "http://repo.maven.apache.org/maven2" } - } - if (JavaVersion.current().isJava8Compatible()) { // Java 8 turns on doclint which we fail tasks.withType(Javadoc) { @@ -136,23 +138,6 @@ subprojects { build.dependsOn(checkstyleTest) build.dependsOn(javadocJar) - shadowJar { - classifier 'dist' - dependencies { - include(dependency('com.sk89q:jchronic:0.2.4a')) - include(dependency('com.thoughtworks.paranamer:paranamer:2.6')) - include(dependency('com.sk89q.lib:jlibnoise:1.0.0')) - include(dependency('net.kyori:text-api:2.0.0')) - include(dependency("net.kyori:text-serializer-gson:2.0.0")) - include(dependency("net.kyori:text-serializer-legacy:2.0.0")) - - relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting.text') - } - exclude 'GradleStart**' - exclude '.cache' - exclude 'LICENSE*' - } - artifactoryPublish { publishConfigs('archives') } @@ -162,3 +147,16 @@ subprojects { include '**/*.java' } } + +configure(['bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) { + shadowJar { + classifier 'dist' + dependencies { + include(project(":worldedit-libs")) + include(project(":worldedit-core")) + } + exclude 'GradleStart**' + exclude '.cache' + exclude 'LICENSE*' + } +} diff --git a/settings.gradle b/settings.gradle index 576283ecc..efbda026f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,8 @@ rootProject.name = 'worldedit' -include 'worldedit-core', 'worldedit-bukkit', 'worldedit-forge', 'worldedit-sponge' \ No newline at end of file +include 'worldedit-libs' + +['bukkit', 'core', 'forge', 'sponge'].forEach { + include "worldedit-libs:$it" + include "worldedit-$it" +} \ No newline at end of file diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 67ca5e43b..79ec8f5c5 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -10,12 +10,11 @@ repositories { dependencies { compile project(':worldedit-core') + compile project(':worldedit-libs:bukkit') compile 'com.sk89q:dummypermscompat:1.10' compile 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz - compile 'org.bstats:bstats-bukkit:1.4' compile "io.papermc:paperlib:1.0.1" compile 'org.slf4j:slf4j-jdk14:1.7.26' - compile 'net.kyori:text-adapter-bukkit:1.0.3' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java index 21d08d726..b82dfe458 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java @@ -26,8 +26,8 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.auth.AuthorizationException; -import net.kyori.text.TextComponent; -import net.kyori.text.adapter.bukkit.TextAdapter; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index ca15daa91..71941a69d 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -37,8 +37,8 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; -import net.kyori.text.TextComponent; -import net.kyori.text.adapter.bukkit.TextAdapter; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index 9d8176407..c401d5b06 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -4,20 +4,15 @@ apply plugin: 'eclipse' apply plugin: 'idea' dependencies { + compile project(':worldedit-libs:core') compile 'de.schlichtherle:truezip:6.8.3' compile 'rhino:js:1.7R2' compile 'org.yaml:snakeyaml:1.9' compile 'com.google.guava:guava:21.0' - compile 'com.sk89q:jchronic:0.2.4a' compile 'com.google.code.findbugs:jsr305:1.3.9' - compile 'com.thoughtworks.paranamer:paranamer:2.6' compile 'com.google.code.gson:gson:2.8.0' - compile 'com.sk89q.lib:jlibnoise:1.0.0' compile 'com.googlecode.json-simple:json-simple:1.1.1' compile 'org.slf4j:slf4j-api:1.7.26' - compile 'net.kyori:text-api:2.0.0' - compile 'net.kyori:text-serializer-gson:2.0.0' - compile 'net.kyori:text-serializer-legacy:2.0.0' //compile 'net.sf.trove4j:trove4j:3.0.3' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index ee93e847c..7c1b1889c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -62,7 +62,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.storage.ChunkStore; -import net.kyori.text.Component; +import com.sk89q.worldedit.util.formatting.text.Component; import java.util.ArrayList; import java.util.List; @@ -75,7 +75,7 @@ import java.util.Set; public class SelectionCommands { private final WorldEdit we; - + public SelectionCommands(WorldEdit we) { this.we = we; } @@ -294,7 +294,7 @@ public class SelectionCommands { ) @CommandPermissions("worldedit.wand.toggle") public void toggleWand(Player player, LocalSession session, CommandContext args) throws WorldEditException { - + session.setToolControl(!session.isToolControlEnabled()); if (session.isToolControlEnabled()) { @@ -393,7 +393,7 @@ public class SelectionCommands { session.getRegionSelector(player.getWorld()).learnChanges(); int newSize = region.getArea(); - + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); player.print("Region expanded " + (newSize - oldSize) + " blocks."); @@ -464,7 +464,7 @@ public class SelectionCommands { } session.getRegionSelector(player.getWorld()).learnChanges(); int newSize = region.getArea(); - + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index e8ee6275f..989fbad6b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -65,9 +65,9 @@ import com.sk89q.worldedit.util.formatting.component.Error; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; import java.util.ArrayList; import java.util.List; @@ -207,7 +207,7 @@ public class UtilityCommands { @CommandPermissions("worldedit.removeabove") @Logging(PLACEMENT) public void removeAbove(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - + int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; we.checkMaxRadius(size); World world = player.getWorld(); @@ -275,7 +275,7 @@ public class UtilityCommands { @CommandPermissions("worldedit.replacenear") @Logging(PLACEMENT) public void replaceNear(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - + int size = Math.max(1, args.getInteger(0)); we.checkMaxRadius(size); int affected; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java index 86bae5934..45160de66 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java @@ -23,7 +23,7 @@ import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionOwner; import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.auth.Subject; -import net.kyori.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import java.io.File; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java index 5211e1380..2159a2fce 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java @@ -34,7 +34,7 @@ import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.gamemode.GameMode; -import net.kyori.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import java.util.UUID; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java index ec9164c72..a1491551e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java @@ -19,8 +19,8 @@ package com.sk89q.worldedit.util.formatting.component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a fragment representing a command that is to be typed. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java index 2767ff920..9e6ec3295 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -19,9 +19,9 @@ package com.sk89q.worldedit.util.formatting.component; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; public class CommandListBox extends MessageBox { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index fb0cc5c60..13eee701c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -28,8 +28,8 @@ import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.util.command.Description; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.PrimaryAliasComparator; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import java.util.ArrayList; import java.util.List; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java index 5042a3804..52d9d7044 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java @@ -19,8 +19,8 @@ package com.sk89q.worldedit.util.formatting.component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a fragment representing an error. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java index bc0e46527..a38adc7bb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java @@ -19,8 +19,8 @@ package com.sk89q.worldedit.util.formatting.component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a fragment representing a label. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java index 7b2dcc72e..b32c00995 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java @@ -21,9 +21,9 @@ package com.sk89q.worldedit.util.formatting.component; import static com.google.common.base.Preconditions.checkNotNull; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Makes for a box with a border above and below. @@ -67,7 +67,7 @@ public class MessageBox extends TextComponent { /** * Get the internal contents. - * + * * @return the contents */ public Component getContents() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java index 68600f0a3..a512138d4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java @@ -19,8 +19,8 @@ package com.sk89q.worldedit.util.formatting.component; -import net.kyori.text.TextComponent; -import net.kyori.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a subtle part of the message. diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index 57734f43a..5dc11aaf6 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -34,7 +34,7 @@ import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; -import net.kyori.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle new file mode 100644 index 000000000..51b307019 --- /dev/null +++ b/worldedit-libs/build.gradle @@ -0,0 +1,97 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +subprojects { + apply plugin: 'maven' + apply plugin: 'com.github.johnrengelman.shadow' + apply plugin: 'com.jfrog.artifactory' + configurations { + create("shade") + } + + group = rootProject.group + ".worldedit-libs" + + tasks.register("jar", ShadowJar) { + configurations = [project.configurations.shade] + classifier = "" + + relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting.text') + } + def altConfigFiles = { String artifactType -> + def deps = configurations.shade.incoming.dependencies + .collect { it.copy() } + .collect { dependency -> + dependency.artifact { artifact -> + artifact.name = dependency.name + artifact.type = artifactType + artifact.extension = 'jar' + artifact.classifier = artifactType + } + dependency + } + + return files(configurations.detachedConfiguration(deps as Dependency[]) + .resolvedConfiguration.lenientConfiguration.getArtifacts() + .findAll { it.classifier == artifactType } + .collect { zipTree(it.file) }) + } + tasks.register("sourcesJar", Jar) { + from { + altConfigFiles('sources') + } + def filePattern = ~'(.*)net/kyori/text((?:/|$).*)' + def textPattern = ~/net\.kyori\.text/ + eachFile { + it.filter { String line -> + line.replaceFirst(textPattern, 'com.sk89q.worldedit.util.formatting.text') + } + it.path = it.path.replaceFirst(filePattern, '$1com/sk89q/worldedit/util/formatting/text$2') + } + classifier = "sources" + } + + artifacts { + add("default", jar) + add("default", sourcesJar) + } + + tasks.register("install", Upload) { + configuration = configurations.default + repositories.mavenInstaller { + pom.version = project.version + pom.artifactId = project.name + } + } + + artifactoryPublish { + publishConfigs('default') + } + + build.dependsOn(jar, sourcesJar) +} + +project("core") { + dependencies { + shade 'net.kyori:text-api:2.0.0' + shade 'net.kyori:text-serializer-gson:2.0.0' + shade 'net.kyori:text-serializer-legacy:2.0.0' + shade 'com.sk89q:jchronic:0.2.4a' + shade 'com.thoughtworks.paranamer:paranamer:2.6' + shade 'com.sk89q.lib:jlibnoise:1.0.0' + } +} +project("bukkit") { + dependencies { + shade 'net.kyori:text-adapter-bukkit:1.0.3' + shade 'org.bstats:bstats-bukkit:1.4' + } +} +project("sponge") { + dependencies { + shade 'net.kyori:text-adapter-spongeapi:1.0.3' + shade 'org.bstats:bstats-sponge:1.4' + } +} + +tasks.register("build") { + dependsOn(subprojects.collect { it.tasks.named("build") }) +} diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle index 762557b6e..422913966 100644 --- a/worldedit-sponge/build.gradle +++ b/worldedit-sponge/build.gradle @@ -17,9 +17,8 @@ repositories { dependencies { compile project(':worldedit-core') + compile project(':worldedit-libs:sponge') compile 'org.spongepowered:spongeapi:7.1.0' - compile 'org.bstats:bstats-sponge:1.4' - compile 'net.kyori:text-adapter-spongeapi:1.0.3' testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1' } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java index fe5c626a3..e44146b3c 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java @@ -26,8 +26,8 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.auth.AuthorizationException; -import net.kyori.text.TextComponent; -import net.kyori.text.adapter.spongeapi.TextAdapter; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.adapter.spongeapi.TextAdapter; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java index 10b1f47e8..099780b3d 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java @@ -36,8 +36,8 @@ import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemTypes; -import net.kyori.text.TextComponent; -import net.kyori.text.adapter.spongeapi.TextAdapter; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.adapter.spongeapi.TextAdapter; import org.spongepowered.api.Sponge; import org.spongepowered.api.data.type.HandTypes; import org.spongepowered.api.entity.living.player.Player; From 5c19866809a7c5a4856eb2e1ed079fdb86e1a9d5 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 20 Apr 2019 23:33:54 -0700 Subject: [PATCH 030/366] Some fixes for new libs shading --- build.gradle | 3 ++- worldedit-bukkit/build.gradle | 1 + worldedit-core/build.gradle | 7 ------- worldedit-forge/build.gradle | 2 -- worldedit-libs/build.gradle | 11 ++++++----- worldedit-sponge/build.gradle | 11 ++++------- 6 files changed, 13 insertions(+), 22 deletions(-) diff --git a/build.gradle b/build.gradle index 16fd983db..eaa4a49b5 100644 --- a/build.gradle +++ b/build.gradle @@ -152,7 +152,8 @@ configure(['bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) { shadowJar { classifier 'dist' dependencies { - include(project(":worldedit-libs")) + include(project(":worldedit-libs:core")) + include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}")) include(project(":worldedit-core")) } exclude 'GradleStart**' diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 79ec8f5c5..14550bdb5 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -15,6 +15,7 @@ dependencies { compile 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz compile "io.papermc:paperlib:1.0.1" compile 'org.slf4j:slf4j-jdk14:1.7.26' + compile 'org.bstats:bstats-bukkit:1.4' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index c401d5b06..828833d9a 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -1,5 +1,3 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - apply plugin: 'eclipse' apply plugin: 'idea' @@ -28,8 +26,3 @@ sourceSets { } } } - -task jar(type: ShadowJar, overwrite: true) { - from sourceSets.main.output - configurations = [project.configurations.runtime] -} \ No newline at end of file diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index c1ce166c1..d398d05d1 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -88,10 +88,8 @@ shadowJar { relocate "org.slf4j", "com.sk89q.worldedit.slf4j" relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge" - include(dependency(':worldedit-core')) include(dependency('org.slf4j:slf4j-api')) include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) - include(dependency("net.kyori:text-serializer-gson:2.0.0")) } } diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 51b307019..983d2dc41 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -6,6 +6,7 @@ subprojects { apply plugin: 'com.jfrog.artifactory' configurations { create("shade") + getByName("archives").extendsFrom(getByName("default")) } group = rootProject.group + ".worldedit-libs" @@ -51,11 +52,11 @@ subprojects { artifacts { add("default", jar) - add("default", sourcesJar) + add("archives", sourcesJar) } tasks.register("install", Upload) { - configuration = configurations.default + configuration = configurations.archives repositories.mavenInstaller { pom.version = project.version pom.artifactId = project.name @@ -74,7 +75,9 @@ project("core") { shade 'net.kyori:text-api:2.0.0' shade 'net.kyori:text-serializer-gson:2.0.0' shade 'net.kyori:text-serializer-legacy:2.0.0' - shade 'com.sk89q:jchronic:0.2.4a' + shade('com.sk89q:jchronic:0.2.4a') { + exclude(group: "junit", module: "junit") + } shade 'com.thoughtworks.paranamer:paranamer:2.6' shade 'com.sk89q.lib:jlibnoise:1.0.0' } @@ -82,13 +85,11 @@ project("core") { project("bukkit") { dependencies { shade 'net.kyori:text-adapter-bukkit:1.0.3' - shade 'org.bstats:bstats-bukkit:1.4' } } project("sponge") { dependencies { shade 'net.kyori:text-adapter-spongeapi:1.0.3' - shade 'org.bstats:bstats-sponge:1.4' } } diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle index 422913966..6d75c4d84 100644 --- a/worldedit-sponge/build.gradle +++ b/worldedit-sponge/build.gradle @@ -19,6 +19,7 @@ dependencies { compile project(':worldedit-core') compile project(':worldedit-libs:sponge') compile 'org.spongepowered:spongeapi:7.1.0' + compile 'org.bstats:bstats-sponge:1.4' testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1' } @@ -40,16 +41,12 @@ jar { shadowJar { dependencies { - include(dependency(':worldedit-core')) - include(dependency('org.bstats:bstats-sponge:1.4')) - include(dependency("net.kyori:text-adapter-spongeapi:1.0.3")) + relocate ("org.bstats", "com.sk89q.worldedit.sponge.bstats") { + include(dependency('org.bstats:bstats-sponge:1.4')) + } } } -artifacts { - archives shadowJar -} - if (project.hasProperty("signing")) { apply plugin: 'signing' From 73d56819269eeb730fb99373f482513f75aeb1b9 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 20 Apr 2019 23:36:44 -0700 Subject: [PATCH 031/366] Add a note about which libraries get shaded where --- worldedit-libs/build.gradle | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 983d2dc41..81d44c28c 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -1,5 +1,17 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +/* +This project shades API libraries, i.e. those libraries +whose classes are publicly referenced from `-core` classes. + +This project does not shade implementation libraries, i.e. +those libraries whose classes are internally depended on. + +This is because the main reason for shading those libraries is for +their internal usage in each platform, not because we need them available to +dependents of `-core` to compile and work with WorldEdit's API. + + */ subprojects { apply plugin: 'maven' apply plugin: 'com.github.johnrengelman.shadow' From 5a18ed275ff3ab3707c39cf8b9e76e5ad4f746e9 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 21 Apr 2019 00:01:06 -0700 Subject: [PATCH 032/366] Drop provided / compileOnly dependencies from shadow --- worldedit-libs/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 81d44c28c..f0a2359b5 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -27,6 +27,12 @@ subprojects { configurations = [project.configurations.shade] classifier = "" + dependencies { + exclude(dependency("com.google.guava:guava")) + exclude(dependency("com.google.code.gson:gson")) + exclude(dependency("org.checkerframework:checker-qual")) + } + relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting.text') } def altConfigFiles = { String artifactType -> From 51be16ad81b5af8754d0256c3e776c3b98196a68 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 21 Apr 2019 13:10:20 -0700 Subject: [PATCH 033/366] Port GeneralCommands --- .../worldedit/command/GeneralCommands.java | 127 ++++++++---------- .../platform/PlatformCommandMananger.java | 8 +- 2 files changed, 63 insertions(+), 72 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index b05adf155..a5a0a9796 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -19,28 +19,31 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.collect.Sets; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; + +import static com.google.common.base.Preconditions.checkNotNull; /** * General WorldEdit commands. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class GeneralCommands { private final WorldEdit worldEdit; @@ -56,19 +59,18 @@ public class GeneralCommands { } @Command( - aliases = { "/limit" }, - usage = "[limit]", - desc = "Modify block change limit", - min = 0, - max = 1 + name = "/limit", + desc = "Modify block change limit" ) @CommandPermissions("worldedit.limit") - public void limit(Player player, LocalSession session, CommandContext args) throws WorldEditException { - + public void limit(Player player, LocalSession session, + @Arg(desc = "The limit to set", def = "") + Integer limit) throws WorldEditException { + LocalConfiguration config = worldEdit.getConfiguration(); boolean mayDisable = player.hasPermission("worldedit.limit.unrestricted"); - int limit = args.argsLength() == 0 ? config.defaultChangeLimit : Math.max(-1, args.getInteger(0)); + limit = limit == null ? config.defaultChangeLimit : Math.max(-1, limit); if (!mayDisable && config.maxChangeLimit > -1) { if (limit > config.maxChangeLimit) { player.printError("Your maximum allowable limit is " + config.maxChangeLimit + "."); @@ -86,19 +88,18 @@ public class GeneralCommands { } @Command( - aliases = { "/timeout" }, - usage = "[time]", - desc = "Modify evaluation timeout time.", - min = 0, - max = 1 + name = "/timeout", + desc = "Modify evaluation timeout time." ) @CommandPermissions("worldedit.timeout") - public void timeout(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void timeout(Player player, LocalSession session, + @Arg(desc = "The timeout time to set", def = "") + Integer limit) throws WorldEditException { LocalConfiguration config = worldEdit.getConfiguration(); boolean mayDisable = player.hasPermission("worldedit.timeout.unrestricted"); - int limit = args.argsLength() == 0 ? config.calculationTimeout : Math.max(-1, args.getInteger(0)); + limit = limit == null ? config.calculationTimeout : Math.max(-1, limit); if (!mayDisable && config.maxCalculationTimeout > -1) { if (limit > config.maxCalculationTimeout) { player.printError("Your maximum allowable timeout is " + config.maxCalculationTimeout + " ms."); @@ -116,16 +117,14 @@ public class GeneralCommands { } @Command( - aliases = { "/fast" }, - usage = "[on|off]", - desc = "Toggle fast mode", - min = 0, - max = 1 + name = "/fast", + desc = "Toggle fast mode" ) @CommandPermissions("worldedit.fast") - public void fast(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void fast(Player player, LocalSession session, + @Arg(name = "on|off", desc = "The new fast mode state", def = "toggle") + String newState) throws WorldEditException { - String newState = args.getString(0, null); if (session.hasFastMode()) { if ("on".equals(newState)) { player.printError("Fast mode already enabled."); @@ -146,15 +145,13 @@ public class GeneralCommands { } @Command( - aliases = { "/reorder" }, - usage = "[multi|fast|none]", - desc = "Sets the reorder mode of WorldEdit", - min = 0, - max = 1 + name = "/reorder", + desc = "Sets the reorder mode of WorldEdit" ) @CommandPermissions("worldedit.reorder") - public void reorderMode(Player player, LocalSession session, CommandContext args) throws WorldEditException { - String newState = args.getString(0, null); + public void reorderMode(Player player, LocalSession session, + @Arg(name = "multi|fast|none", desc = "The reorder mode", def = "") + String newState) throws WorldEditException { if (newState == null) { player.print("The reorder mode is " + session.getReorderMode().getDisplayName()); } else { @@ -171,19 +168,16 @@ public class GeneralCommands { } @Command( - aliases = { "/drawsel" }, - usage = "[on|off]", - desc = "Toggle drawing the current selection", - min = 0, - max = 1 + name = "/drawsel", + desc = "Toggle drawing the current selection" ) @CommandPermissions("worldedit.drawsel") - public void drawSelection(Player player, LocalSession session, CommandContext args) throws WorldEditException { - + public void drawSelection(Player player, LocalSession session, + @Arg(name = "on|off", desc = "The new fast mode state", def = "toggle") + String newState) throws WorldEditException { if (!WorldEdit.getInstance().getConfiguration().serverSideCUI) { throw new DisallowedUsageException("This functionality is disabled in the configuration!"); } - String newState = args.getString(0, null); if (session.shouldUseServerCUI()) { if ("on".equals(newState)) { player.printError("Server CUI already enabled."); @@ -206,14 +200,14 @@ public class GeneralCommands { } @Command( - aliases = { "/gmask", "gmask" }, - usage = "[mask]", - desc = "Set the global mask", - min = 0, - max = -1 + name = "gmask", + aliases = {"/gmask"}, + desc = "Set the global mask" ) @CommandPermissions("worldedit.global-mask") - public void gmask(Player player, LocalSession session, @Optional Mask mask) throws WorldEditException { + public void gmask(Player player, LocalSession session, + @Arg(desc = "The mask to set", def = "") + Mask mask) throws WorldEditException { if (mask == null) { session.setMask((Mask) null); player.print("Global mask disabled."); @@ -224,11 +218,9 @@ public class GeneralCommands { } @Command( - aliases = { "/toggleplace", "toggleplace" }, - usage = "", - desc = "Switch between your position and pos1 for placement", - min = 0, - max = 0 + name = "toggleplace", + aliases = {"/toggleplace"}, + desc = "Switch between your position and pos1 for placement" ) public void togglePlace(Player player, LocalSession session) throws WorldEditException { @@ -240,24 +232,17 @@ public class GeneralCommands { } @Command( - aliases = { "/searchitem", "/l", "/search", "searchitem" }, - usage = "", - flags = "bi", - desc = "Search for an item", - help = - "Searches for an item.\n" + - "Flags:\n" + - " -b only search for blocks\n" + - " -i only search for items", - min = 1, - max = 1 + name = "searchitem", + aliases = {"/searchitem", "/l", "/search"}, + desc = "Search for an item" ) - public void searchItem(Actor actor, CommandContext args) throws WorldEditException { - - String query = args.getString(0).trim().toLowerCase(); - boolean blocksOnly = args.hasFlag('b'); - boolean itemsOnly = args.hasFlag('i'); - + public void searchItem(Actor actor, + @Arg(desc = "Item query") + String query, + @Switch(name = 'b', desc = "Only search for blocks") + boolean blocksOnly, + @Switch(name = 'i', desc = "Only search for items") + boolean itemsOnly) throws WorldEditException { ItemType type = ItemTypes.get(query); if (type != null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index df71157f7..8df64ab03 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -33,6 +33,8 @@ import com.sk89q.worldedit.command.ChunkCommands; import com.sk89q.worldedit.command.ChunkCommandsRegistration; import com.sk89q.worldedit.command.ClipboardCommands; import com.sk89q.worldedit.command.ClipboardCommandsRegistration; +import com.sk89q.worldedit.command.GeneralCommands; +import com.sk89q.worldedit.command.GeneralCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; @@ -251,13 +253,17 @@ public final class PlatformCommandMananger { ClipboardCommandsRegistration.builder(), new ClipboardCommands() ); + register( + commandManager, + GeneralCommandsRegistration.builder(), + new GeneralCommands(worldEdit) + ); // Unported commands are below. Delete once they're added to the main manager above. /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new GeneralCommands(worldEdit)) .registerMethods(new GenerationCommands(worldEdit)) .registerMethods(new HistoryCommands(worldEdit)) .registerMethods(new NavigationCommands(worldEdit)) From c52eb59d7f702dbcc90c47ad9aae7fedacf72e1b Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 22 Apr 2019 22:05:20 +1000 Subject: [PATCH 034/366] Get it all working --- build.gradle | 1 + worldedit-bukkit/build.gradle | 1 - .../worldedit/command/SelectionCommands.java | 21 +++++---- .../worldedit/command/UtilityCommands.java | 20 ++++---- .../extension/platform/CommandManager.java | 2 +- .../util/formatting/component/Code.java | 5 +- .../formatting/component/CommandListBox.java | 16 ++++++- .../formatting/component/CommandUsageBox.java | 17 ++++--- .../util/formatting/component/Error.java | 5 +- .../util/formatting/component/Label.java | 5 +- .../util/formatting/component/MessageBox.java | 22 +++++---- .../util/formatting/component/Subtle.java | 5 +- .../component/TextComponentProducer.java | 47 +++++++++++++++++++ worldedit-libs/build.gradle | 4 +- 14 files changed, 116 insertions(+), 55 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java diff --git a/build.gradle b/build.gradle index eaa4a49b5..63b4d9537 100644 --- a/build.gradle +++ b/build.gradle @@ -86,6 +86,7 @@ subprojects { mavenCentral() maven { url "http://maven.sk89q.com/repo/" } maven { url "http://repo.maven.apache.org/maven2" } + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } } } diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 14550bdb5..975aee9d9 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -43,7 +43,6 @@ shadowJar { include(dependency(':worldedit-core')) include(dependency('org.slf4j:slf4j-api')) include(dependency("org.slf4j:slf4j-jdk14")) - include(dependency("net.kyori:text-adapter-bukkit:1.0.3")) relocate ("org.bstats", "com.sk89q.worldedit.bukkit.bstats") { include(dependency("org.bstats:bstats-bukkit:1.4")) } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 7c1b1889c..cd15be1ff 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -57,6 +57,7 @@ import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.component.CommandListBox; import com.sk89q.worldedit.util.formatting.component.Subtle; +import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -753,18 +754,18 @@ public class SelectionCommands { limit.ifPresent(integer -> player.print(integer + " points maximum.")); } else { CommandListBox box = new CommandListBox("Selection modes"); - Component contents = box.getContents(); - contents.append(new Subtle("Select one of the modes below:").append(Component.newline())); + TextComponentProducer contents = box.getContents(); + contents.append(new Subtle("Select one of the modes below:").append(Component.newline()).create()); - box.appendCommand("cuboid", "Select two corners of a cuboid"); - box.appendCommand("extend", "Fast cuboid selection mode"); - box.appendCommand("poly", "Select a 2D polygon with height"); - box.appendCommand("ellipsoid", "Select an ellipsoid"); - box.appendCommand("sphere", "Select a sphere"); - box.appendCommand("cyl", "Select a cylinder"); - box.appendCommand("convex", "Select a convex polyhedral"); + box.appendCommand("cuboid", "Select two corners of a cuboid", "//sel cuboid"); + box.appendCommand("extend", "Fast cuboid selection mode", "//sel extend"); + box.appendCommand("poly", "Select a 2D polygon with height", "//sel poly"); + box.appendCommand("ellipsoid", "Select an ellipsoid", "//sel ellipsoid"); + box.appendCommand("sphere", "Select a sphere", "//sel sphere"); + box.appendCommand("cyl", "Select a cylinder", "//sel cyl"); + box.appendCommand("convex", "Select a convex polyhedral", "//sel convex"); - player.print(box); + player.print(box.create()); return; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 989fbad6b..bd0c8ba53 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -62,12 +62,13 @@ import com.sk89q.worldedit.util.formatting.component.Code; import com.sk89q.worldedit.util.formatting.component.CommandListBox; import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; import com.sk89q.worldedit.util.formatting.component.Error; +import com.sk89q.worldedit.util.formatting.component.Subtle; +import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.format.TextColor; import java.util.ArrayList; import java.util.List; @@ -670,16 +671,16 @@ public class UtilityCommands { // Box CommandListBox box = new CommandListBox(String.format("Help: page %d/%d ", page + 1, pageTotal)); - Component contents = box.getContents(); - Component tip = contents.append(TextComponent.of("", TextColor.GRAY)); + TextComponentProducer tip = new Subtle(""); + TextComponentProducer contents = box.getContents(); if (offset >= aliases.size()) { - tip.append(new Error(String.format("There is no page %d (total number of pages is %d).", page + 1, pageTotal))).append(Component.newline()); + tip.append(new Error(String.format("There is no page %d (total number of pages is %d).", page + 1, pageTotal)).create()).append(Component.newline()); } else { List list = aliases.subList(offset, Math.min(offset + perPage, aliases.size())); tip.append(TextComponent.of("Type ")); - tip.append(new Code("//help ").append(TextComponent.of(" []"))); + tip.append(new Code("//help ").append(TextComponent.of(" []")).create()); tip.append(TextComponent.of(" for more information.")).append(Component.newline()); // Add each command @@ -697,10 +698,11 @@ public class UtilityCommands { } } - actor.print(box); + contents.append(tip.create()); + actor.print(box.create()); } else { CommandUsageBox box = new CommandUsageBox(callable, Joiner.on(" ").join(visited)); - actor.print(box); + actor.print(box.create()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index 11257efdf..45b5265bb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -299,7 +299,7 @@ public final class CommandManager { actor.printError("You are not permitted to do that. Are you in the right mode?"); } catch (InvalidUsageException e) { if (e.isFullHelpSuggested()) { - actor.print(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals)); + actor.print(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals).create()); String message = e.getMessage(); if (message != null) { actor.printError(message); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java index a1491551e..6cbad7f3a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java @@ -19,19 +19,18 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a fragment representing a command that is to be typed. */ -public class Code extends TextComponent { +public class Code extends TextComponentProducer { /** * Create a new instance. */ public Code(String message) { - super(builder(message).color(TextColor.AQUA)); + getBuilder().content(message).color(TextColor.AQUA); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java index 9e6ec3295..846d08853 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -21,6 +21,8 @@ package com.sk89q.worldedit.util.formatting.component; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; public class CommandListBox extends MessageBox { @@ -33,14 +35,24 @@ public class CommandListBox extends MessageBox { * @param title the title */ public CommandListBox(String title) { - super(title); + super(title, new TextComponentProducer()); } public CommandListBox appendCommand(String alias, String description) { + return appendCommand(alias, description, null); + } + + public CommandListBox appendCommand(String alias, String description, String insertion) { if (!first) { getContents().append(Component.newline()); } - getContents().append(TextComponent.of(alias, TextColor.GOLD).append(TextComponent.of(": "))); + TextComponent commandName = TextComponent.of(alias, TextColor.GOLD); + if (insertion != null) { + commandName = commandName + .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, insertion)) + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select"))); + } + getContents().append(commandName.append(TextComponent.of(": "))); getContents().append(TextComponent.of(description)); first = false; return this; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index 13eee701c..e15d862cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -39,7 +39,7 @@ import javax.annotation.Nullable; /** * A box to describe usage of a command. */ -public class CommandUsageBox extends TextComponent { +public class CommandUsageBox extends TextComponentProducer { /** * Create a new usage box. @@ -59,7 +59,6 @@ public class CommandUsageBox extends TextComponent { * @param locals list of locals to use */ public CommandUsageBox(CommandCallable command, String commandString, @Nullable CommandLocals locals) { - super(builder()); checkNotNull(command); checkNotNull(commandString); if (command instanceof Dispatcher) { @@ -82,18 +81,17 @@ public class CommandUsageBox extends TextComponent { } } - append(box); + append(box.create()); } private void attachCommandUsage(Description description, String commandString) { - MessageBox box = new MessageBox("Help for " + commandString); - Component contents = box.getContents(); + TextComponentProducer contents = new TextComponentProducer(); if (description.getUsage() != null) { - contents.append(new Label("Usage: ")); + contents.append(new Label("Usage: ").create()); contents.append(TextComponent.of(description.getUsage())); } else { - contents.append(new Subtle("Usage information is not available.")); + contents.append(new Subtle("Usage information is not available.").create()); } contents.append(Component.newline()); @@ -103,10 +101,11 @@ public class CommandUsageBox extends TextComponent { } else if (description.getDescription() != null) { contents.append(TextComponent.of(description.getDescription())); } else { - contents.append(new Subtle("No further help is available.")); + contents.append(new Subtle("No further help is available.").create()); } - append(box); + MessageBox box = new MessageBox("Help for " + commandString, contents); + append(box.create()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java index 52d9d7044..50cef22f2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java @@ -19,19 +19,18 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a fragment representing an error. */ -public class Error extends TextComponent { +public class Error extends TextComponentProducer { /** * Create a new instance. */ public Error(String message) { - super(builder(message).color(TextColor.RED)); + getBuilder().content(message).color(TextColor.RED); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java index a38adc7bb..02d438f8d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java @@ -19,19 +19,18 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a fragment representing a label. */ -public class Label extends TextComponent { +public class Label extends TextComponentProducer { /** * Create a new instance. */ public Label(String message) { - super(builder(message).color(TextColor.YELLOW)); + getBuilder().content(message).color(TextColor.YELLOW); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java index b32c00995..5193f0e6b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java @@ -28,17 +28,16 @@ import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Makes for a box with a border above and below. */ -public class MessageBox extends TextComponent { +public class MessageBox extends TextComponentProducer { - public static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 47; + private static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 47; - private final Component contents = Component.empty(); + private final TextComponentProducer contents; /** * Create a new box. */ - public MessageBox(String title) { - super(builder()); + public MessageBox(String title, TextComponentProducer contents) { checkNotNull(title); int leftOver = GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH - title.length() - 2; @@ -54,7 +53,7 @@ public class MessageBox extends TextComponent { append(TextComponent.of(createBorder(rightSide), TextColor.YELLOW)); } append(Component.newline()); - append(contents); + this.contents = contents; } private String createBorder(int count) { @@ -66,12 +65,17 @@ public class MessageBox extends TextComponent { } /** - * Get the internal contents. + * Gets the message box contents producer. * - * @return the contents + * @return The contents producer */ - public Component getContents() { + public TextComponentProducer getContents() { return contents; } + @Override + public TextComponent create() { + append(contents.create()); + return super.create(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java index a512138d4..609824838 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java @@ -19,19 +19,18 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a subtle part of the message. */ -public class Subtle extends TextComponent { +public class Subtle extends TextComponentProducer { /** * Create a new instance. */ public Subtle(String message) { - super(builder(message).color(TextColor.GRAY)); + getBuilder().color(TextColor.GRAY).content(message); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java new file mode 100644 index 000000000..2c3228ee2 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java @@ -0,0 +1,47 @@ +/* + * 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.util.formatting.component; + +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; + +public class TextComponentProducer { + + private TextComponent.Builder builder = TextComponent.builder().content(""); + + public TextComponent.Builder getBuilder() { + return builder; + } + + /** + * Adds a component as a child to this Producer + * + * @param component The component + * @return The producer, for chaining + */ + public TextComponentProducer append(Component component) { + getBuilder().append(component); + return this; + } + + public TextComponent create() { + return builder.build(); + } +} diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index f0a2359b5..b05c601e8 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -102,12 +102,12 @@ project("core") { } project("bukkit") { dependencies { - shade 'net.kyori:text-adapter-bukkit:1.0.3' + shade 'net.kyori:text-adapter-bukkit:2.0.0-SNAPSHOT' } } project("sponge") { dependencies { - shade 'net.kyori:text-adapter-spongeapi:1.0.3' + shade 'net.kyori:text-adapter-spongeapi:2.0.0-SNAPSHOT' } } From 0434bcf48cd1eaa32eed5f841d0ffe7a8cff3354 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 22 Apr 2019 23:59:31 +1000 Subject: [PATCH 035/366] Remove unnecessary gradle entries --- build.gradle | 1 - worldedit-forge/build.gradle | 1 - 2 files changed, 2 deletions(-) diff --git a/build.gradle b/build.gradle index 63b4d9537..41de17bb8 100644 --- a/build.gradle +++ b/build.gradle @@ -85,7 +85,6 @@ subprojects { repositories { mavenCentral() maven { url "http://maven.sk89q.com/repo/" } - maven { url "http://repo.maven.apache.org/maven2" } maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } } } diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index d398d05d1..2cbab094f 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -19,7 +19,6 @@ def forgeVersion = "25.0.76" dependencies { compile project(':worldedit-core') compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.2' - compile 'net.kyori:text-serializer-gson:2.0.0' minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}" From 31486cd47389d700cf81ca403c50e5549a3ed017 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 23 Apr 2019 10:11:54 -0700 Subject: [PATCH 036/366] Port generation commands --- .../worldedit/command/GenerationCommands.java | 298 +++++++++--------- .../CommaSeparatedValuesConverter.java | 68 ++++ ...tternParser.java => PatternConverter.java} | 45 +-- .../command/argument/ReplaceParser.java | 8 +- .../extension/platform/Annotations.java | 16 + .../platform/PlatformCommandMananger.java | 20 +- .../worldedit/internal/annotation/Radii.java | 40 +++ 7 files changed, 321 insertions(+), 174 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java rename worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/{PatternParser.java => PatternConverter.java} (60%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Annotations.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Radii.java 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 f4578bdcd..962243c9f 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 @@ -19,35 +19,39 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; -import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; -import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.Radii; import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.TreeGenerator.TreeType; -import com.sk89q.worldedit.util.command.binding.Range; -import com.sk89q.worldedit.util.command.binding.Switch; -import com.sk89q.worldedit.util.command.binding.Text; -import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.world.biome.BiomeType; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; +import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; +import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; /** * Commands for the generation of shapes and other objects. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class GenerationCommands { private final WorldEdit worldEdit; @@ -63,54 +67,52 @@ public class GenerationCommands { } @Command( - aliases = { "/hcyl" }, - usage = " [,] [height]", - desc = "Generates a hollow cylinder.", - help = - "Generates a hollow cylinder.\n" + - "By specifying 2 radii, separated by a comma,\n" + - "you can generate elliptical cylinders.\n" + - "The 1st radius is north/south, the 2nd radius is east/west.", - min = 2, - max = 3 + name = "/hcyl", + desc = "Generates a hollow cylinder." ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) - public void hcyl(Player player, LocalSession session, EditSession editSession, Pattern pattern, String radiusString, @Optional("1") int height) throws WorldEditException { - cyl(player, session, editSession, pattern, radiusString, height, true); + public int hcyl(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to generate") + Pattern pattern, + @Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W") + @Radii(2) + List radii, + @Arg(desc = "The height of the cylinder", def = "1") + int height) throws WorldEditException { + return cyl(player, session, editSession, pattern, radii, height, true); } @Command( - aliases = { "/cyl" }, - usage = " [,] [height]", - flags = "h", - desc = "Generates a cylinder.", - help = - "Generates a cylinder.\n" + - "By specifying 2 radii, separated by a comma,\n" + - "you can generate elliptical cylinders.\n" + - "The 1st radius is north/south, the 2nd radius is east/west.", - min = 2, - max = 3 + name = "/cyl", + desc = "Generates a cylinder." ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) - public void cyl(Player player, LocalSession session, EditSession editSession, Pattern pattern, String radiusString, @Optional("1") int height, @Switch('h') boolean hollow) throws WorldEditException { - String[] radii = radiusString.split(","); + public int cyl(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to generate") + Pattern pattern, + @Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W") + @Radii(2) + List radii, + @Arg(desc = "The height of the cylinder", def = "1") + int height, + @Switch(name = 'h', desc = "Make a hollow cylinder") + boolean hollow) throws WorldEditException { final double radiusX, radiusZ; - switch (radii.length) { + switch (radii.size()) { case 1: - radiusX = radiusZ = Math.max(1, Double.parseDouble(radii[0])); + radiusX = radiusZ = Math.max(1, radii.get(0)); break; case 2: - radiusX = Math.max(1, Double.parseDouble(radii[0])); - radiusZ = Math.max(1, Double.parseDouble(radii[1])); + radiusX = Math.max(1, radii.get(0)); + radiusZ = Math.max(1, radii.get(1)); break; default: player.printError("You must either specify 1 or 2 radius values."); - return; + return 0; } worldEdit.checkMaxRadius(radiusX); @@ -120,58 +122,57 @@ public class GenerationCommands { BlockVector3 pos = session.getPlacementPosition(player); int affected = editSession.makeCylinder(pos, pattern, radiusX, radiusZ, height, !hollow); player.print(affected + " block(s) have been created."); + return affected; } @Command( - aliases = { "/hsphere" }, - usage = " [,,] [raised?]", - desc = "Generates a hollow sphere.", - help = - "Generates a hollow sphere.\n" + - "By specifying 3 radii, separated by commas,\n" + - "you can generate an ellipsoid. The order of the ellipsoid radii\n" + - "is north/south, up/down, east/west.", - min = 2, - max = 3 + name = "/hsphere", + desc = "Generates a hollow sphere." ) @CommandPermissions("worldedit.generation.sphere") @Logging(PLACEMENT) - public void hsphere(Player player, LocalSession session, EditSession editSession, Pattern pattern, String radiusString, @Optional("false") boolean raised) throws WorldEditException { - sphere(player, session, editSession, pattern, radiusString, raised, true); + public int hsphere(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to generate") + Pattern pattern, + @Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W") + @Radii(3) + List radii, + @Switch(name = 'r', desc = "Raise the bottom of the sphere to the placement position") + boolean raised) throws WorldEditException { + return sphere(player, session, editSession, pattern, radii, raised, true); } @Command( - aliases = { "/sphere" }, - usage = " [,,] [raised?]", - flags = "h", - desc = "Generates a filled sphere.", - help = - "Generates a filled sphere.\n" + - "By specifying 3 radii, separated by commas,\n" + - "you can generate an ellipsoid. The order of the ellipsoid radii\n" + - "is north/south, up/down, east/west.", - min = 2, - max = 3 + name = "/sphere", + desc = "Generates a filled sphere." ) @CommandPermissions("worldedit.generation.sphere") @Logging(PLACEMENT) - public void sphere(Player player, LocalSession session, EditSession editSession, Pattern pattern, String radiusString, @Optional("false") boolean raised, @Switch('h') boolean hollow) throws WorldEditException { - String[] radii = radiusString.split(","); + public int sphere(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to generate") + Pattern pattern, + @Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W") + @Radii(3) + List radii, + @Switch(name = 'r', desc = "Raise the bottom of the sphere to the placement position") + boolean raised, + @Switch(name = 'h', desc = "Make a hollow sphere") + boolean hollow) throws WorldEditException { final double radiusX, radiusY, radiusZ; - switch (radii.length) { + switch (radii.size()) { case 1: - radiusX = radiusY = radiusZ = Math.max(1, Double.parseDouble(radii[0])); + radiusX = radiusY = radiusZ = Math.max(1, radii.get(0)); break; case 3: - radiusX = Math.max(1, Double.parseDouble(radii[0])); - radiusY = Math.max(1, Double.parseDouble(radii[1])); - radiusZ = Math.max(1, Double.parseDouble(radii[2])); + radiusX = Math.max(1, radii.get(0)); + radiusY = Math.max(1, radii.get(1)); + radiusZ = Math.max(1, radii.get(2)); break; default: player.printError("You must either specify 1 or 3 radius values."); - return; + return 0; } worldEdit.checkMaxRadius(radiusX); @@ -186,98 +187,102 @@ public class GenerationCommands { int affected = editSession.makeSphere(pos, pattern, radiusX, radiusY, radiusZ, !hollow); player.findFreePosition(); player.print(affected + " block(s) have been created."); + return affected; } @Command( - aliases = { "forestgen" }, - usage = "[size] [type] [density]", - desc = "Generate a forest", - min = 0, - max = 3 + name = "forestgen", + desc = "Generate a forest" ) @CommandPermissions("worldedit.generation.forest") @Logging(POSITION) - public void forestGen(Player player, LocalSession session, EditSession editSession, @Optional("10") int size, - @Optional("tree") TreeType type, @Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException { + public int forestGen(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The size of the forest, in blocks", def = "10") + int size, + @Arg(desc = "The type of forest", def = "tree") + TreeType type, + @Arg(desc = "The density of the forest, between 0 and 100", def = "5") + double density) throws WorldEditException { + if (density < 0 || density > 100) { + throw new IllegalArgumentException("Density must be between 0 and 100"); + } density = density / 100; int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); player.print(affected + " trees created."); + return affected; } @Command( - aliases = { "pumpkins" }, - usage = "[size]", - desc = "Generate pumpkin patches", - min = 0, - max = 1 + name = "pumpkins", + desc = "Generate pumpkin patches" ) @CommandPermissions("worldedit.generation.pumpkins") @Logging(POSITION) - public void pumpkins(Player player, LocalSession session, EditSession editSession, @Optional("10") int apothem) throws WorldEditException { - int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), apothem); + public int pumpkins(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The size of the patch", def = "10") + int size) throws WorldEditException { + int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), size); player.print(affected + " pumpkin patches created."); + return affected; } @Command( - aliases = { "/hpyramid" }, - usage = " ", - desc = "Generate a hollow pyramid", - min = 2, - max = 2 + name = "/hpyramid", + desc = "Generate a hollow pyramid" ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) - public void hollowPyramid(Player player, LocalSession session, EditSession editSession, Pattern pattern, @Range(min = 1) int size) throws WorldEditException { - pyramid(player, session, editSession, pattern, size, true); + public int hollowPyramid(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern, + @Arg(desc = "The size of the pyramid") + int size) throws WorldEditException { + return pyramid(player, session, editSession, pattern, size, true); } @Command( - aliases = { "/pyramid" }, - usage = " ", - flags = "h", - desc = "Generate a filled pyramid", - min = 2, - max = 2 + name = "/pyramid", + desc = "Generate a filled pyramid" ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) - public void pyramid(Player player, LocalSession session, EditSession editSession, Pattern pattern, @Range(min = 1) int size, @Switch('h') boolean hollow) throws WorldEditException { + public int pyramid(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern, + @Arg(desc = "The size of the pyramid") + int size, + @Switch(name = 'h', desc = "Make a hollow pyramid") + boolean hollow) throws WorldEditException { BlockVector3 pos = session.getPlacementPosition(player); worldEdit.checkMaxRadius(size); int affected = editSession.makePyramid(pos, pattern, size, !hollow); player.findFreePosition(); player.print(affected + " block(s) have been created."); + return affected; } @Command( - aliases = { "/generate", "/gen", "/g" }, - usage = " ", + name = "/generate", + aliases = { "/gen", "/g" }, desc = "Generates a shape according to a formula.", - help = - "Generates a shape according to a formula that is expected to\n" + - "return positive numbers (true) if the point is inside the shape\n" + - "Optionally set type/data to the desired block.\n" + - "Flags:\n" + - " -h to generate a hollow shape\n" + - " -r to use raw minecraft coordinates\n" + - " -o is like -r, except offset from placement.\n" + - " -c is like -r, except offset selection center.\n" + - "If neither -r nor -o is given, the selection is mapped to -1..1\n" + - "See also tinyurl.com/wesyntax.", - flags = "hroc", - min = 2, - max = -1 + descFooter = "See also https://tinyurl.com/wesyntax." ) @CommandPermissions("worldedit.generation.shape") @Logging(ALL) - public void generate(Player player, LocalSession session, EditSession editSession, - @Selection Region region, - Pattern pattern, - @Text String expression, - @Switch('h') boolean hollow, - @Switch('r') boolean useRawCoords, - @Switch('o') boolean offset, - @Switch('c') boolean offsetCenter) throws WorldEditException { + public int generate(Player player, LocalSession session, EditSession editSession, + @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern, + @Arg(desc = "Expression to test block placement locations and set block type") + String expression, + @Switch(name = 'h', desc = "Generate a hollow shape") + boolean hollow, + @Switch(name = 'r', desc = "Use the game's coordinate origin") + boolean useRawCoords, + @Switch(name = 'o', desc = "Use the placement's coordinate origin") + boolean offset, + @Switch(name = 'c', desc = "Use the selection's center as origin") + boolean offsetCenter) throws WorldEditException { final Vector3 zero; Vector3 unit; @@ -310,40 +315,35 @@ public class GenerationCommands { final int affected = editSession.makeShape(region, zero, unit, pattern, expression, hollow, session.getTimeout()); player.findFreePosition(); player.print(affected + " block(s) have been created."); + return affected; } catch (ExpressionException e) { player.printError(e.getMessage()); + return 0; } } @Command( - aliases = { "/generatebiome", "/genbiome", "/gb" }, - usage = " ", + name = "/generatebiome", + aliases = { "/genbiome", "/gb" }, desc = "Sets biome according to a formula.", - help = - "Generates a shape according to a formula that is expected to\n" + - "return positive numbers (true) if the point is inside the shape\n" + - "Sets the biome of blocks in that shape.\n" + - "Flags:\n" + - " -h to generate a hollow shape\n" + - " -r to use raw minecraft coordinates\n" + - " -o is like -r, except offset from placement.\n" + - " -c is like -r, except offset selection center.\n" + - "If neither -r nor -o is given, the selection is mapped to -1..1\n" + - "See also tinyurl.com/wesyntax.", - flags = "hroc", - min = 2, - max = -1 + descFooter = "See also https://tinyurl.com/wesyntax." ) @CommandPermissions("worldedit.generation.shape.biome") @Logging(ALL) - public void generateBiome(Player player, LocalSession session, EditSession editSession, - @Selection Region region, - BiomeType target, - @Text String expression, - @Switch('h') boolean hollow, - @Switch('r') boolean useRawCoords, - @Switch('o') boolean offset, - @Switch('c') boolean offsetCenter) throws WorldEditException { + public int generateBiome(Player player, LocalSession session, EditSession editSession, + @Selection Region region, + @Arg(desc = "The biome type to set") + BiomeType target, + @Arg(desc = "Expression to test block placement locations and set biome type") + String expression, + @Switch(name = 'h', desc = "Generate a hollow shape") + boolean hollow, + @Switch(name = 'r', desc = "Use the game's coordinate origin") + boolean useRawCoords, + @Switch(name = 'o', desc = "Use the placement's coordinate origin") + boolean offset, + @Switch(name = 'c', desc = "Use the selection's center as origin") + boolean offsetCenter) throws WorldEditException { final Vector3 zero; Vector3 unit; @@ -375,8 +375,10 @@ public class GenerationCommands { final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow, session.getTimeout()); player.findFreePosition(); player.print("" + affected + " columns affected."); + return affected; } catch (ExpressionException e) { player.printError(e.getMessage()); + return 0; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java new file mode 100644 index 000000000..f4b2cafa5 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java @@ -0,0 +1,68 @@ +package com.sk89q.worldedit.command.argument; + +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; + +public class CommaSeparatedValuesConverter implements ArgumentConverter { + + public static CommaSeparatedValuesConverter wrap(ArgumentConverter delegate) { + return wrapAndLimit(delegate, -1); + } + + public static CommaSeparatedValuesConverter wrapAndLimit(ArgumentConverter delegate, int maximum) { + return new CommaSeparatedValuesConverter<>(delegate, maximum); + } + + private static final Splitter COMMA = Splitter.on(','); + + private final ArgumentConverter delegate; + private final int maximum; + + private CommaSeparatedValuesConverter(ArgumentConverter delegate, int maximum) { + checkArgument(maximum == -1 || maximum > 1, + "Maximum must be bigger than 1, or exactly -1"); + this.delegate = delegate; + this.maximum = maximum; + } + + @Override + public String describeAcceptableArguments() { + StringBuilder result = new StringBuilder(); + if (maximum > -1) { + result.append("up to ").append(maximum).append(' '); + } + result.append("comma separated values of ") + .append(delegate.describeAcceptableArguments()); + result.setCharAt(0, Character.toUpperCase(result.charAt(0))); + return result.toString(); + } + + @Override + public List getSuggestions(String input) { + String lastInput = Iterables.getLast(COMMA.split(input)); + return delegate.getSuggestions(lastInput); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + ImmutableList.Builder result = ImmutableList.builder(); + for (String input : COMMA.split(argument)) { + ConversionResult temp = delegate.convert(input, context); + if (!temp.isSuccessful()) { + return temp; + } + result.addAll(temp.get()); + } + return SuccessfulConversion.from(result.build()); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternConverter.java similarity index 60% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternParser.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternConverter.java index e8d209e4c..3155c17f5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternConverter.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.command.argument; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Entity; @@ -29,23 +27,30 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.composition.SimpleCommand; import com.sk89q.worldedit.world.World; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; -public class PatternParser extends SimpleCommand { +public class PatternConverter implements ArgumentConverter { - private final StringParser stringParser; + public static void register(WorldEdit worldEdit, CommandManager commandManager) { + commandManager.registerConverter(Key.of(Pattern.class), new PatternConverter(worldEdit)); + } - public PatternParser(String name) { - stringParser = addParameter(new StringParser(name, "The pattern")); + private final WorldEdit worldEdit; + + private PatternConverter(WorldEdit worldEdit) { + this.worldEdit = worldEdit; } @Override - public Pattern call(CommandArgs args, CommandLocals locals) throws CommandException { - String patternString = stringParser.call(args, locals); - - Actor actor = locals.get(Actor.class); + public ConversionResult convert(String argument, InjectedValueAccess context) { + Actor actor = context.injectedValue(Key.of(Actor.class)) + .orElseThrow(() -> new IllegalStateException("No actor")); LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); ParserContext parserContext = new ParserContext(); @@ -59,20 +64,16 @@ public class PatternParser extends SimpleCommand { parserContext.setSession(session); try { - return WorldEdit.getInstance().getPatternFactory().parseFromInput(patternString, parserContext); + return SuccessfulConversion.fromSingle( + worldEdit.getPatternFactory().parseFromInput(argument, parserContext) + ); } catch (InputParseException e) { - throw new CommandException(e.getMessage(), e); + throw new IllegalArgumentException(e); } } @Override - public String getDescription() { - return "Choose a pattern"; + public String describeAcceptableArguments() { + return "any pattern"; } - - @Override - public boolean testPermission0(CommandLocals locals) { - return true; - } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ReplaceParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ReplaceParser.java index 4d98103c3..eebfb4a16 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ReplaceParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ReplaceParser.java @@ -35,12 +35,14 @@ import com.sk89q.worldedit.util.command.composition.SimpleCommand; public class ReplaceParser extends SimpleCommand> { - private final PatternParser fillArg = addParameter(new PatternParser("fillPattern")); + // TODO rewrite for new system +// private final PatternParser fillArg = addParameter(new PatternParser("fillPattern")); @Override public Contextual call(CommandArgs args, CommandLocals locals) throws CommandException { - Pattern fill = fillArg.call(args, locals); - return new ReplaceFactory(fill); +// Pattern fill = fillArg.call(args, locals); +// return new ReplaceFactory(fill); + return null; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Annotations.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Annotations.java new file mode 100644 index 000000000..08ad84d6c --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Annotations.java @@ -0,0 +1,16 @@ +package com.sk89q.worldedit.extension.platform; + +import com.google.auto.value.AutoAnnotation; +import com.sk89q.worldedit.internal.annotation.Radii; + +/** + * Holder for generated annotation classes. + */ +class Annotations { + + @AutoAnnotation + static Radii radii(int value) { + return new AutoAnnotation_Annotations_radii(value); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 8df64ab03..d40c2e39e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extension.platform; import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalConfiguration; @@ -35,11 +36,15 @@ import com.sk89q.worldedit.command.ClipboardCommands; import com.sk89q.worldedit.command.ClipboardCommandsRegistration; import com.sk89q.worldedit.command.GeneralCommands; import com.sk89q.worldedit.command.GeneralCommandsRegistration; +import com.sk89q.worldedit.command.GenerationCommands; +import com.sk89q.worldedit.command.GenerationCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; +import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; import com.sk89q.worldedit.command.argument.DirectionConverter; import com.sk89q.worldedit.command.argument.MaskConverter; +import com.sk89q.worldedit.command.argument.PatternConverter; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Entity; @@ -65,6 +70,7 @@ import com.sk89q.worldedit.world.World; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; import org.enginehub.piston.DefaultCommandManagerService; +import org.enginehub.piston.converter.ArgumentConverters; import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.CommandExecutionException; import org.enginehub.piston.exception.ConditionFailedException; @@ -171,6 +177,14 @@ public final class PlatformCommandMananger { private void registerArgumentConverters() { DirectionConverter.register(worldEdit, commandManager); MaskConverter.register(worldEdit, commandManager); + PatternConverter.register(worldEdit, commandManager); + for (int count = 2; count <= 3; count++) { + commandManager.registerConverter(Key.of(double.class, Annotations.radii(count)), + CommaSeparatedValuesConverter.wrapAndLimit(ArgumentConverters.get( + TypeToken.of(double.class) + ), count) + ); + } } private void registerAlwaysInjectedValues() { @@ -258,13 +272,17 @@ public final class PlatformCommandMananger { GeneralCommandsRegistration.builder(), new GeneralCommands(worldEdit) ); + register( + commandManager, + GenerationCommandsRegistration.builder(), + new GenerationCommands(worldEdit) + ); // Unported commands are below. Delete once they're added to the main manager above. /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new GenerationCommands(worldEdit)) .registerMethods(new HistoryCommands(worldEdit)) .registerMethods(new NavigationCommands(worldEdit)) .registerMethods(new RegionCommands(worldEdit)) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Radii.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Radii.java new file mode 100644 index 000000000..82423fba9 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/Radii.java @@ -0,0 +1,40 @@ +/* + * 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.internal.annotation; + +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates a {@code double} parameter to inject multiple radii values. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface Radii { + /** + * Number of radii values to inject at maximum. May inject less. + */ + int value(); +} From 20da6227d474562796d184c0fd410b573c54f8f0 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 23 Apr 2019 15:35:05 -0700 Subject: [PATCH 037/366] Port history commands --- .../worldedit/command/HistoryCommands.java | 82 ++++++++++--------- .../platform/PlatformCommandMananger.java | 7 ++ 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index b960dfbe4..b9a247132 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -19,20 +19,23 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; + +import static com.google.common.base.Preconditions.checkNotNull; /** * Commands to undo, redo, and clear history. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.class) public class HistoryCommands { private final WorldEdit worldEdit; @@ -48,28 +51,29 @@ public class HistoryCommands { } @Command( - aliases = { "/undo", "undo" }, - usage = "[times] [player]", - desc = "Undoes the last action", - min = 0, - max = 2 + name = "undo", + aliases = { "/undo" }, + desc = "Undoes the last action (from history)" ) @CommandPermissions("worldedit.history.undo") - public void undo(Player player, LocalSession session, CommandContext args) throws WorldEditException { - int times = Math.max(1, args.getInteger(0, 1)); + public void undo(Player player, LocalSession session, + @Arg(desc = "Number of undoes to perform", def = "1") + int times, + @Arg(name = "player", desc = "Undo this player's operations", def = "") + String playerName) throws WorldEditException { + times = Math.max(1, times); for (int i = 0; i < times; ++i) { - EditSession undone; - if (args.argsLength() < 2) { - undone = session.undo(session.getBlockBag(player), player); - } else { + LocalSession undoSession = session; + if (playerName != null) { player.checkPermission("worldedit.history.undo.other"); - LocalSession sess = worldEdit.getSessionManager().findByName(args.getString(1)); + LocalSession sess = worldEdit.getSessionManager().findByName(playerName); if (sess == null) { - player.printError("Unable to find session for " + args.getString(1)); + player.printError("Unable to find session for " + playerName); break; } - undone = sess.undo(session.getBlockBag(player), player); + undoSession = session; } + EditSession undone = undoSession.undo(undoSession.getBlockBag(player), player); if (undone != null) { player.print("Undo successful."); worldEdit.flushBlockBag(player, undone); @@ -81,45 +85,43 @@ public class HistoryCommands { } @Command( - aliases = { "/redo", "redo" }, - usage = "[times] [player]", - desc = "Redoes the last action (from history)", - min = 0, - max = 2 + name = "redo", + aliases = { "redo" }, + desc = "Redoes the last action (from history)" ) @CommandPermissions("worldedit.history.redo") - public void redo(Player player, LocalSession session, CommandContext args) throws WorldEditException { - - int times = Math.max(1, args.getInteger(0, 1)); - + public void redo(Player player, LocalSession session, + @Arg(desc = "Number of redoes to perform", def = "1") + int times, + @Arg(name = "player", desc = "Redo this player's operations", def = "") + String playerName) throws WorldEditException { + times = Math.max(1, times); for (int i = 0; i < times; ++i) { - EditSession redone; - if (args.argsLength() < 2) { - redone = session.redo(session.getBlockBag(player), player); - } else { + LocalSession redoSession = session; + if (playerName != null) { player.checkPermission("worldedit.history.redo.other"); - LocalSession sess = worldEdit.getSessionManager().findByName(args.getString(1)); + LocalSession sess = worldEdit.getSessionManager().findByName(playerName); if (sess == null) { - player.printError("Unable to find session for " + args.getString(1)); + player.printError("Unable to find session for " + playerName); break; } - redone = sess.redo(session.getBlockBag(player), player); + redoSession = session; } + EditSession redone = redoSession.redo(redoSession.getBlockBag(player), player); if (redone != null) { player.print("Redo successful."); worldEdit.flushBlockBag(player, redone); } else { player.printError("Nothing left to redo."); + break; } } } @Command( - aliases = { "/clearhistory", "clearhistory" }, - usage = "", - desc = "Clear your history", - min = 0, - max = 0 + name = "clearhistory", + aliases = { "/clearhistory" }, + desc = "Clear your history" ) @CommandPermissions("worldedit.history.clear") public void clearHistory(Player player, LocalSession session) throws WorldEditException { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index d40c2e39e..8f0e0a8d7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -38,6 +38,8 @@ import com.sk89q.worldedit.command.GeneralCommands; import com.sk89q.worldedit.command.GeneralCommandsRegistration; import com.sk89q.worldedit.command.GenerationCommands; import com.sk89q.worldedit.command.GenerationCommandsRegistration; +import com.sk89q.worldedit.command.HistoryCommands; +import com.sk89q.worldedit.command.HistoryCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; @@ -277,6 +279,11 @@ public final class PlatformCommandMananger { GenerationCommandsRegistration.builder(), new GenerationCommands(worldEdit) ); + register( + commandManager, + HistoryCommandsRegistration.builder(), + new HistoryCommands(worldEdit) + ); // Unported commands are below. Delete once they're added to the main manager above. /* From 6d4982f23aa1c2ef774deae950b6b7df1df7eb7e Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 23 Apr 2019 15:44:33 -0700 Subject: [PATCH 038/366] Fix checkstyle/license/gen code --- .../worldedit/command/HistoryCommands.java | 8 +++---- .../CommaSeparatedValuesConverter.java | 19 ++++++++++++++++ .../CommandPermissionsConditionGenerator.java | 2 +- .../extension/platform/Annotations.java | 22 +++++++++++++++++++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index b9a247132..c5bb07699 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -35,7 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Commands to undo, redo, and clear history. */ -@CommandContainer(superTypes = CommandPermissionsConditionGenerator.class) +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class HistoryCommands { private final WorldEdit worldEdit; @@ -58,9 +58,9 @@ public class HistoryCommands { @CommandPermissions("worldedit.history.undo") public void undo(Player player, LocalSession session, @Arg(desc = "Number of undoes to perform", def = "1") - int times, + int times, @Arg(name = "player", desc = "Undo this player's operations", def = "") - String playerName) throws WorldEditException { + String playerName) throws WorldEditException { times = Math.max(1, times); for (int i = 0; i < times; ++i) { LocalSession undoSession = session; @@ -86,7 +86,7 @@ public class HistoryCommands { @Command( name = "redo", - aliases = { "redo" }, + aliases = { "/redo" }, desc = "Redoes the last action (from history)" ) @CommandPermissions("worldedit.history.redo") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java index f4b2cafa5..d2947a44a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java @@ -1,3 +1,22 @@ +/* + * 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.command.argument; import com.google.common.base.Splitter; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java index b126198a6..f0de910e8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java @@ -31,7 +31,7 @@ import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; @NonnullByDefault -public class CommandPermissionsConditionGenerator implements CommandConditionGenerator { +public final class CommandPermissionsConditionGenerator implements CommandConditionGenerator { public interface Registration { Registration commandPermissionsConditionGenerator(CommandPermissionsConditionGenerator generator); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Annotations.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Annotations.java index 08ad84d6c..f1f1319e9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Annotations.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Annotations.java @@ -1,3 +1,22 @@ +/* + * 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.extension.platform; import com.google.auto.value.AutoAnnotation; @@ -13,4 +32,7 @@ class Annotations { return new AutoAnnotation_Annotations_radii(value); } + private Annotations() { + } + } From f2283e8ad019a342eef8e8863a15a9d2b9842d55 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 23 Apr 2019 16:14:21 -0700 Subject: [PATCH 039/366] Port navigation commands --- .../worldedit/command/NavigationCommands.java | 126 +++++++++--------- .../platform/PlatformCommandMananger.java | 9 +- 2 files changed, 67 insertions(+), 68 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java index b2fb9c4cb..0b70e0bd7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java @@ -19,23 +19,26 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.command.parametric.Optional; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; /** * Commands for moving the player around. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class NavigationCommands { private final WorldEdit worldEdit; @@ -51,80 +54,78 @@ public class NavigationCommands { } @Command( - aliases = { "unstuck", "!" }, - usage = "", - desc = "Escape from being stuck inside a block", - min = 0, - max = 0 + name = "unstuck", + aliases = { "!" }, + desc = "Escape from being stuck inside a block" ) @CommandPermissions("worldedit.navigation.unstuck") public void unstuck(Player player) throws WorldEditException { - player.print("There you go!"); player.findFreePosition(); + player.print("There you go!"); } @Command( - aliases = { "ascend", "asc" }, - usage = "[# of levels]", - desc = "Go up a floor", - min = 0, - max = 1 + name = "ascend", + aliases = { "asc" }, + desc = "Go up a floor" ) @CommandPermissions("worldedit.navigation.ascend") - public void ascend(Player player, @Optional("1") int levelsToAscend) throws WorldEditException { + public void ascend(Player player, + @Arg(desc = "# of levels to ascend", def = "1") + int levels) throws WorldEditException { int ascentLevels = 0; while (player.ascendLevel()) { ++ascentLevels; - if (levelsToAscend == ascentLevels) { + if (levels == ascentLevels) { break; } } if (ascentLevels == 0) { player.printError("No free spot above you found."); } else { - player.print((ascentLevels != 1) ? "Ascended " + Integer.toString(ascentLevels) + " levels." : "Ascended a level."); + player.print((ascentLevels != 1) ? "Ascended " + ascentLevels + " levels." : "Ascended a level."); } } @Command( - aliases = { "descend", "desc" }, - usage = "[# of floors]", - desc = "Go down a floor", - min = 0, - max = 1 + name = "descend", + aliases = { "desc" }, + desc = "Go down a floor" ) @CommandPermissions("worldedit.navigation.descend") - public void descend(Player player, @Optional("1") int levelsToDescend) throws WorldEditException { + public void descend(Player player, + @Arg(desc = "# of levels to descend", def = "1") + int levels) throws WorldEditException { int descentLevels = 0; while (player.descendLevel()) { ++descentLevels; - if (levelsToDescend == descentLevels) { + if (levels == descentLevels) { break; } } if (descentLevels == 0) { player.printError("No free spot below you found."); } else { - player.print((descentLevels != 1) ? "Descended " + Integer.toString(descentLevels) + " levels." : "Descended a level."); + player.print((descentLevels != 1) ? "Descended " + descentLevels + " levels." : "Descended a level."); } } @Command( - aliases = { "ceil" }, - usage = "[clearance]", - desc = "Go to the celing", - flags = "fg", - min = 0, - max = 1 + name = "ceil", + desc = "Go to the ceiling" ) @CommandPermissions("worldedit.navigation.ceiling") @Logging(POSITION) - public void ceiling(Player player, CommandContext args) throws WorldEditException { + public void ceiling(Player player, + @Arg(desc = "# of blocks to leave above you", def = "0") + int clearance, + @Switch(name = 'f', desc = "Force using flight to keep you still") + boolean forceFlight, + @Switch(name = 'g', desc = "Force using glass to keep you still") + boolean forceGlass) throws WorldEditException { + clearance = Math.max(0, clearance); - final int clearance = args.argsLength() > 0 ? - Math.max(0, args.getInteger(0)) : 0; - - final boolean alwaysGlass = getAlwaysGlass(args); + boolean alwaysGlass = getAlwaysGlass(forceFlight, forceGlass); if (player.ascendToCeiling(clearance, alwaysGlass)) { player.print("Whoosh!"); } else { @@ -133,11 +134,8 @@ public class NavigationCommands { } @Command( - aliases = { "thru" }, - usage = "", - desc = "Passthrough walls", - min = 0, - max = 0 + name = "thru", + desc = "Pass through walls" ) @CommandPermissions("worldedit.navigation.thru.command") public void thru(Player player) throws WorldEditException { @@ -149,11 +147,9 @@ public class NavigationCommands { } @Command( - aliases = { "jumpto", "j" }, - usage = "", - desc = "Teleport to a location", - min = 0, - max = 0 + name = "jumpto", + aliases = { "j" }, + desc = "Teleport to a location" ) @CommandPermissions("worldedit.navigation.jumpto.command") public void jumpTo(Player player) throws WorldEditException { @@ -168,19 +164,19 @@ public class NavigationCommands { } @Command( - aliases = { "up" }, - usage = "", - desc = "Go upwards some distance", - flags = "fg", - min = 1, - max = 1 + name = "up", + desc = "Go upwards some distance" ) @CommandPermissions("worldedit.navigation.up") @Logging(POSITION) - public void up(Player player, CommandContext args) throws WorldEditException { - final int distance = args.getInteger(0); - - final boolean alwaysGlass = getAlwaysGlass(args); + public void up(Player player, + @Arg(desc = "Distance to go upwards") + int distance, + @Switch(name = 'f', desc = "Force using flight to keep you still") + boolean forceFlight, + @Switch(name = 'g', desc = "Force using glass to keep you still") + boolean forceGlass) throws WorldEditException { + boolean alwaysGlass = getAlwaysGlass(forceFlight, forceGlass); if (player.ascendUpwards(distance, alwaysGlass)) { player.print("Whoosh!"); } else { @@ -190,16 +186,14 @@ public class NavigationCommands { /** * Helper function for /up and /ceil. - * - * @param args The {@link CommandContext} to extract the flags from. + * + * @param forceFlight if flight should be used, rather than the default config option + * @param forceGlass if glass should always be placed, rather than the default config option * @return true, if glass should always be put under the player */ - private boolean getAlwaysGlass(CommandContext args) { + private boolean getAlwaysGlass(boolean forceFlight, boolean forceGlass) { final LocalConfiguration config = worldEdit.getConfiguration(); - final boolean forceFlight = args.hasFlag('f'); - final boolean forceGlass = args.hasFlag('g'); - return forceGlass || (config.navigationUseGlass && !forceFlight); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 8f0e0a8d7..59013d552 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -40,6 +40,8 @@ import com.sk89q.worldedit.command.GenerationCommands; import com.sk89q.worldedit.command.GenerationCommandsRegistration; import com.sk89q.worldedit.command.HistoryCommands; import com.sk89q.worldedit.command.HistoryCommandsRegistration; +import com.sk89q.worldedit.command.NavigationCommands; +import com.sk89q.worldedit.command.NavigationCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; @@ -284,14 +286,17 @@ public final class PlatformCommandMananger { HistoryCommandsRegistration.builder(), new HistoryCommands(worldEdit) ); + register( + commandManager, + NavigationCommandsRegistration.builder(), + new NavigationCommands(worldEdit) + ); // Unported commands are below. Delete once they're added to the main manager above. /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new HistoryCommands(worldEdit)) - .registerMethods(new NavigationCommands(worldEdit)) .registerMethods(new RegionCommands(worldEdit)) .registerMethods(new ScriptingCommands(worldEdit)) .registerMethods(new SelectionCommands(worldEdit)) From 6415d0d9645b7520d1dd21158acf605b5bd33040 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Sun, 21 Apr 2019 05:09:51 +0200 Subject: [PATCH 040/366] Fix typo --- .../java/com/sk89q/worldedit/function/mask/NoiseFilter.java | 2 +- .../java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java index ee9b6e44d..c870d4786 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter.java @@ -80,7 +80,7 @@ public class NoiseFilter extends AbstractMask { */ public void setDensity(double density) { checkArgument(density >= 0, "density must be >= 0"); - checkArgument(density <= 1, "density must be >= 1"); + checkArgument(density <= 1, "density must be <= 1"); this.density = density; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java index a64889f54..f7a2c992e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/NoiseFilter2D.java @@ -78,7 +78,7 @@ public class NoiseFilter2D extends AbstractMask2D { */ public void setDensity(double density) { checkArgument(density >= 0, "density must be >= 0"); - checkArgument(density <= 1, "density must be >= 1"); + checkArgument(density <= 1, "density must be <= 1"); this.density = density; } From f81ffdde0c45e0684659efd960a3aab2a9428646 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 23 Apr 2019 18:46:46 -0700 Subject: [PATCH 041/366] Port region commands --- .../worldedit/command/RegionCommands.java | 367 +++++++++--------- .../platform/PlatformCommandMananger.java | 8 +- .../command/WorldEditExceptionConverter.java | 6 +- 3 files changed, 183 insertions(+), 198 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 093d84f0e..6c5bcbfc2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -19,20 +19,11 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; -import static com.sk89q.worldedit.command.util.Logging.LogMode.ORIENTATION_REGION; -import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; -import static com.sk89q.worldedit.regions.Regions.asFlatRegion; -import static com.sk89q.worldedit.regions.Regions.maximumBlockY; -import static com.sk89q.worldedit.regions.Regions.minimumBlockY; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.GroundFunction; @@ -57,56 +48,54 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.util.TreeGenerator.TreeType; -import com.sk89q.worldedit.util.command.binding.Range; -import com.sk89q.worldedit.util.command.binding.Switch; -import com.sk89q.worldedit.util.command.binding.Text; -import com.sk89q.worldedit.util.command.parametric.Optional; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; import java.util.ArrayList; import java.util.List; +import static com.google.common.base.Preconditions.checkArgument; +import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; +import static com.sk89q.worldedit.command.util.Logging.LogMode.ORIENTATION_REGION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; +import static com.sk89q.worldedit.regions.Regions.asFlatRegion; +import static com.sk89q.worldedit.regions.Regions.maximumBlockY; +import static com.sk89q.worldedit.regions.Regions.minimumBlockY; + /** * Commands that operate on regions. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class RegionCommands { - private final WorldEdit worldEdit; - /** * Create a new instance. - * - * @param worldEdit reference to WorldEdit */ - public RegionCommands(WorldEdit worldEdit) { - checkNotNull(worldEdit); - this.worldEdit = worldEdit; + public RegionCommands() { } @Command( - aliases = { "/line" }, - usage = " [thickness]", - desc = "Draws a line segment between cuboid selection corners", - help = - "Draws a line segment between cuboid selection corners.\n" + - "Can only be used with cuboid selections.\n" + - "Flags:\n" + - " -h generates only a shell", - flags = "h", - min = 1, - max = 2 + name = "/line", + desc = "Draws a line segment between cuboid selection corners", + descFooter = "Can only be used with a cuboid selection" ) @CommandPermissions("worldedit.region.line") @Logging(REGION) - public void line(Player player, EditSession editSession, - @Selection Region region, - Pattern pattern, - @Optional("0") @Range(min = 0) int thickness, - @Switch('h') boolean shell) throws WorldEditException { - + public int line(Player player, EditSession editSession, + @Selection Region region, + @Arg(desc = "The pattern of blocks to place") + Pattern pattern, + @Arg(desc = "The thickness of the line", def = "0") + int thickness, + @Switch(name = 'h', desc = "Generate only a shell") + boolean shell) throws WorldEditException { if (!(region instanceof CuboidRegion)) { player.printError("//line only works with cuboid selections"); - return; + return 0; } + checkArgument(thickness >= 0, "Thickness must be >= 0"); CuboidRegion cuboidregion = (CuboidRegion) region; BlockVector3 pos1 = cuboidregion.getPos1(); @@ -114,32 +103,29 @@ public class RegionCommands { int blocksChanged = editSession.drawLine(pattern, pos1, pos2, thickness, !shell); player.print(blocksChanged + " block(s) have been changed."); + return blocksChanged; } @Command( - aliases = { "/curve" }, - usage = " [thickness]", - desc = "Draws a spline through selected points", - help = - "Draws a spline through selected points.\n" + - "Can only be used with convex polyhedral selections.\n" + - "Flags:\n" + - " -h generates only a shell", - flags = "h", - min = 1, - max = 2 + name = "/curve", + desc = "Draws a spline through selected points", + descFooter = "Can only be used with a convex polyhedral selection" ) @CommandPermissions("worldedit.region.curve") @Logging(REGION) - public void curve(Player player, EditSession editSession, - @Selection Region region, - Pattern pattern, - @Optional("0") @Range(min = 0) int thickness, - @Switch('h') boolean shell) throws WorldEditException { + public int curve(Player player, EditSession editSession, + @Selection Region region, + @Arg(desc = "The pattern of blocks to place") + Pattern pattern, + @Arg(desc = "The thickness of the curve", def = "0") + int thickness, + @Switch(name = 'h', desc = "Generate only a shell") + boolean shell) throws WorldEditException { if (!(region instanceof ConvexPolyhedralRegion)) { player.printError("//curve only works with convex polyhedral selections"); - return; + return 0; } + checkArgument(thickness >= 0, "Thickness must be >= 0"); ConvexPolyhedralRegion cpregion = (ConvexPolyhedralRegion) region; List vectors = new ArrayList<>(cpregion.getVertices()); @@ -147,139 +133,140 @@ public class RegionCommands { int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell); player.print(blocksChanged + " block(s) have been changed."); + return blocksChanged; } @Command( - aliases = { "/replace", "/re", "/rep" }, - usage = "[from-block] ", - desc = "Replace all blocks in the selection with another", - flags = "f", - min = 1, - max = 2 + name = "/replace", + aliases = { "/re", "/rep" }, + desc = "Replace all blocks in the selection with another" ) @CommandPermissions("worldedit.region.replace") @Logging(REGION) - public void replace(Player player, EditSession editSession, @Selection Region region, @Optional Mask from, Pattern to) throws WorldEditException { + public int replace(Player player, EditSession editSession, @Selection Region region, + @Arg(desc = "The mask representing blocks to replace", def = "") + Mask from, + @Arg(desc = "The pattern of blocks to replace with") + Pattern to) throws WorldEditException { if (from == null) { from = new ExistingBlockMask(editSession); } int affected = editSession.replaceBlocks(region, from, to); player.print(affected + " block(s) have been replaced."); + return affected; } @Command( - aliases = { "/overlay" }, - usage = "", - desc = "Set a block on top of blocks in the region", - min = 1, - max = 1 + name = "/overlay", + desc = "Set a block on top of blocks in the region" ) @CommandPermissions("worldedit.region.overlay") @Logging(REGION) - public void overlay(Player player, EditSession editSession, @Selection Region region, Pattern pattern) throws WorldEditException { + public int overlay(Player player, EditSession editSession, @Selection Region region, + @Arg(desc = "The pattern of blocks to overlay") + Pattern pattern) throws WorldEditException { int affected = editSession.overlayCuboidBlocks(region, pattern); player.print(affected + " block(s) have been overlaid."); + return affected; } @Command( - aliases = { "/center", "/middle" }, - usage = "", - desc = "Set the center block(s)", - min = 1, - max = 1 + name = "/center", + aliases = { "/middle" }, + desc = "Set the center block(s)" ) @Logging(REGION) @CommandPermissions("worldedit.region.center") - public void center(Player player, EditSession editSession, @Selection Region region, Pattern pattern) throws WorldEditException { + public int center(Player player, EditSession editSession, @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern) throws WorldEditException { int affected = editSession.center(region, pattern); - player.print("Center set ("+ affected + " blocks changed)"); + player.print("Center set (" + affected + " block(s) changed)"); + return affected; } @Command( - aliases = { "/naturalize" }, - usage = "", - desc = "3 layers of dirt on top then rock below", - min = 0, - max = 0 + name = "/naturalize", + desc = "3 layers of dirt on top then rock below" ) @CommandPermissions("worldedit.region.naturalize") @Logging(REGION) - public void naturalize(Player player, EditSession editSession, @Selection Region region) throws WorldEditException { + public int naturalize(Player player, EditSession editSession, @Selection Region region) throws WorldEditException { int affected = editSession.naturalizeCuboidBlocks(region); player.print(affected + " block(s) have been made to look more natural."); + return affected; } @Command( - aliases = { "/walls" }, - usage = "", - desc = "Build the four sides of the selection", - min = 1, - max = 1 + name = "/walls", + desc = "Build the four sides of the selection" ) @CommandPermissions("worldedit.region.walls") @Logging(REGION) - public void walls(Player player, EditSession editSession, @Selection Region region, Pattern pattern) throws WorldEditException { + public int walls(Player player, EditSession editSession, @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern) throws WorldEditException { int affected = editSession.makeWalls(region, pattern); player.print(affected + " block(s) have been changed."); + return affected; } @Command( - aliases = { "/faces", "/outline" }, - usage = "", - desc = "Build the walls, ceiling, and floor of a selection", - min = 1, - max = 1 + name = "/faces", + aliases = { "/outline" }, + desc = "Build the walls, ceiling, and floor of a selection" ) @CommandPermissions("worldedit.region.faces") @Logging(REGION) - public void faces(Player player, EditSession editSession, @Selection Region region, Pattern pattern) throws WorldEditException { + public int faces(Player player, EditSession editSession, @Selection Region region, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern) throws WorldEditException { int affected = editSession.makeCuboidFaces(region, pattern); player.print(affected + " block(s) have been changed."); + return affected; } @Command( - aliases = { "/smooth" }, - usage = "[iterations] [filter]", + name = "/smooth", desc = "Smooth the elevation in the selection", - help = - "Smooths the elevation in the selection.\n" + - "Optionally, restricts the height map to a set of blocks specified with mask syntax.\n" + - "For example, '//smooth 1 grass_block,dirt,stone' would only smooth natural surface terrain.", - min = 0, - max = 2 + descFooter = "Example: '//smooth 1 grass_block,dirt,stone' would only smooth natural surface terrain." ) @CommandPermissions("worldedit.region.smooth") @Logging(REGION) - public void smooth(Player player, EditSession editSession, @Selection Region region, @Optional("1") int iterations, @Optional Mask mask) throws WorldEditException { + public int smooth(Player player, EditSession editSession, @Selection Region region, + @Arg(desc = "# of iterations to perform", def = "1") + int iterations, + @Arg(desc = "The mask of blocks to use as the height map", def = "") + Mask mask) throws WorldEditException { HeightMap heightMap = new HeightMap(editSession, region, mask); HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); int affected = heightMap.applyFilter(filter, iterations); player.print("Terrain's height map smoothed. " + affected + " block(s) changed."); - + return affected; } @Command( - aliases = { "/move" }, - usage = "[count] [direction] [leave-id]", - flags = "sa", - desc = "Move the contents of the selection", - help = - "Moves the contents of the selection.\n" + - "The -s flag shifts the selection to the target location.\n" + - "The -a flag skips air blocks.\n" + - "Optionally fills the old location with .", - min = 0, - max = 3 + name = "/move", + desc = "Move the contents of the selection" ) @CommandPermissions("worldedit.region.move") @Logging(ORIENTATION_REGION) - public void move(Player player, EditSession editSession, LocalSession session, - @Selection Region region, - @Optional("1") @Range(min = 1) int count, - @Optional(Direction.AIM) @Direction(includeDiagonals = true) BlockVector3 direction, - @Optional("air") Pattern replace, - @Switch('s') boolean moveSelection, - @Switch('a') boolean ignoreAirBlocks) throws WorldEditException { + public int move(Player player, EditSession editSession, LocalSession session, + @Selection Region region, + @Arg(desc = "# of blocks to move", def = "1") + int count, + @Arg(desc = "The direction to move", def = Direction.AIM) + @Direction(includeDiagonals = true) + BlockVector3 direction, + @Arg(desc = "The pattern of blocks to leave", def = "air") + Pattern replace, + @Switch(name = 's', desc = "Shift the selection to the target location") + boolean moveSelection, + @Switch(name = 'a', desc = "Ignore air blocks") + boolean ignoreAirBlocks) throws WorldEditException { + if (count < 1) { + throw new IllegalArgumentException("Count must be >= 1"); + } int affected = editSession.moveRegion(region, direction, count, !ignoreAirBlocks, replace); @@ -294,30 +281,27 @@ public class RegionCommands { } } - player.print(affected + " blocks moved."); + player.print(affected + " block(s) moved."); + return affected; } @Command( - aliases = { "/stack" }, - usage = "[count] [direction]", - flags = "sa", - desc = "Repeat the contents of the selection", - help = - "Repeats the contents of the selection.\n" + - "Flags:\n" + - " -s shifts the selection to the last stacked copy\n" + - " -a skips air blocks", - min = 0, - max = 2 + name = "/stack", + desc = "Repeat the contents of the selection" ) @CommandPermissions("worldedit.region.stack") @Logging(ORIENTATION_REGION) - public void stack(Player player, EditSession editSession, LocalSession session, - @Selection Region region, - @Optional("1") @Range(min = 1) int count, - @Optional(Direction.AIM) @Direction(includeDiagonals = true) BlockVector3 direction, - @Switch('s') boolean moveSelection, - @Switch('a') boolean ignoreAirBlocks) throws WorldEditException { + public int stack(Player player, EditSession editSession, LocalSession session, + @Selection Region region, + @Arg(desc = "# of copies to stack", def = "1") + int count, + @Arg(desc = "The direction to stack", def = Direction.AIM) + @Direction(includeDiagonals = true) + BlockVector3 direction, + @Switch(name = 's', desc = "Shift the selection to the last stacked copy") + boolean moveSelection, + @Switch(name = 'a', desc = "Ignore air blocks") + boolean ignoreAirBlocks) throws WorldEditException { int affected = editSession.stackCuboidRegion(region, direction, count, !ignoreAirBlocks); if (moveSelection) { @@ -334,26 +318,22 @@ public class RegionCommands { } } - player.print(affected + " blocks changed. Undo with //undo"); + player.print(affected + " block(s) changed. Undo with //undo"); + return affected; } @Command( - aliases = { "/regen" }, - usage = "", + name = "/regen", desc = "Regenerates the contents of the selection", - help = - "Regenerates the contents of the current selection.\n" + - "This command might affect things outside the selection,\n" + - "if they are within the same chunk.", - min = 0, - max = 0 + descFooter = "This command might affect things outside the selection,\n" + + "if they are within the same chunk." ) @CommandPermissions("worldedit.regen") @Logging(REGION) public void regenerateChunk(Player player, LocalSession session, EditSession editSession, @Selection Region region) throws WorldEditException { Mask mask = session.getMask(); try { - session.setMask((Mask) null); + session.setMask(null); player.getWorld().regenerate(region, editSession); } finally { session.setMask(mask); @@ -362,25 +342,22 @@ public class RegionCommands { } @Command( - aliases = { "/deform" }, - usage = "", - desc = "Deforms a selected region with an expression", - help = - "Deforms a selected region with an expression\n" + - "The expression is executed for each block and is expected\n" + - "to modify the variables x, y and z to point to a new block\n" + - "to fetch. See also tinyurl.com/wesyntax.", - flags = "ro", - min = 1, - max = -1 + name = "/deform", + desc = "Deforms a selected region with an expression", + descFooter = "The expression is executed for each block and is expected\n" + + "to modify the variables x, y and z to point to a new block\n" + + "to fetch. See also tinyurl.com/wesyntax." ) @CommandPermissions("worldedit.region.deform") @Logging(ALL) - public void deform(Player player, LocalSession session, EditSession editSession, - @Selection Region region, - @Text String expression, - @Switch('r') boolean useRawCoords, - @Switch('o') boolean offset) throws WorldEditException { + public int deform(Player player, LocalSession session, EditSession editSession, + @Selection Region region, + @Arg(desc = "The expression to use") + String expression, + @Switch(name = 'r', desc = "Use the game's coordinate origin") + boolean useRawCoords, + @Switch(name = 'o', desc = "Use the selection's center as origin") + boolean offset) throws WorldEditException { final Vector3 zero; Vector3 unit; @@ -406,58 +383,60 @@ public class RegionCommands { final int affected = editSession.deformRegion(region, zero, unit, expression, session.getTimeout()); player.findFreePosition(); player.print(affected + " block(s) have been deformed."); + return affected; } catch (ExpressionException e) { player.printError(e.getMessage()); + return 0; } } @Command( - aliases = { "/hollow" }, - usage = "[[ ]]", + name = "/hollow", desc = "Hollows out the object contained in this selection", - help = - "Hollows out the object contained in this selection.\n" + - "Optionally fills the hollowed out part with the given block.\n" + - "Thickness is measured in manhattan distance.", - min = 0, - max = 2 + descFooter = "Thickness is measured in manhattan distance." ) @CommandPermissions("worldedit.region.hollow") @Logging(REGION) - public void hollow(Player player, EditSession editSession, - @Selection Region region, - @Optional("0") @Range(min = 0) int thickness, - @Optional("air") Pattern pattern) throws WorldEditException { + public int hollow(Player player, EditSession editSession, + @Selection Region region, + @Arg(desc = "Thickness of the shell to leave", def = "0") + int thickness, + @Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air") + Pattern pattern) throws WorldEditException { + checkArgument(thickness >= 0, "Thickness must be >= 0"); int affected = editSession.hollowOutRegion(region, thickness, pattern); player.print(affected + " block(s) have been changed."); + return affected; } @Command( - aliases = { "/forest" }, - usage = "[type] [density]", - desc = "Make a forest within the region", - min = 0, - max = 2 + name = "/forest", + desc = "Make a forest within the region" ) @CommandPermissions("worldedit.region.forest") @Logging(REGION) - public void forest(Player player, EditSession editSession, @Selection Region region, @Optional("tree") TreeType type, - @Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException { + public int forest(Player player, EditSession editSession, @Selection Region region, + @Arg(desc = "The type of tree to place", def = "tree") + TreeType type, + @Arg(desc = "The density of the forest", def = "5") + double density) throws WorldEditException { + checkArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); int affected = editSession.makeForest(region, density / 100, type); player.print(affected + " trees created."); + return affected; } @Command( - aliases = { "/flora" }, - usage = "[density]", - desc = "Make flora within the region", - min = 0, - max = 1 + name = "/flora", + desc = "Make flora within the region" ) @CommandPermissions("worldedit.region.flora") @Logging(REGION) - public void flora(Player player, EditSession editSession, @Selection Region region, @Optional("10") @Range(min = 0, max = 100) double density) throws WorldEditException { + public int flora(Player player, EditSession editSession, @Selection Region region, + @Arg(desc = "The density of the forest", def = "5") + double density) throws WorldEditException { + checkArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); density = density / 100; FloraGenerator generator = new FloraGenerator(editSession); GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator); @@ -465,7 +444,9 @@ public class RegionCommands { visitor.setMask(new NoiseFilter2D(new RandomNoise(), density)); Operations.completeLegacy(visitor); - player.print(ground.getAffected() + " flora created."); + int affected = ground.getAffected(); + player.print(affected + " flora created."); + return affected; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 59013d552..7dd59b9f2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -42,6 +42,8 @@ import com.sk89q.worldedit.command.HistoryCommands; import com.sk89q.worldedit.command.HistoryCommandsRegistration; import com.sk89q.worldedit.command.NavigationCommands; import com.sk89q.worldedit.command.NavigationCommandsRegistration; +import com.sk89q.worldedit.command.RegionCommands; +import com.sk89q.worldedit.command.RegionCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; @@ -291,13 +293,17 @@ public final class PlatformCommandMananger { NavigationCommandsRegistration.builder(), new NavigationCommands(worldEdit) ); + register( + commandManager, + RegionCommandsRegistration.builder(), + new RegionCommands() + ); // Unported commands are below. Delete once they're added to the main manager above. /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new RegionCommands(worldEdit)) .registerMethods(new ScriptingCommands(worldEdit)) .registerMethods(new SelectionCommands(worldEdit)) .registerMethods(new SnapshotUtilCommands(worldEdit)) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java index 2e9c6fa62..b75d1c5b3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java @@ -163,10 +163,8 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { } @ExceptionMatch - public void convert(ConditionFailedException e) throws CommandException { - if (e.getCondition() instanceof PermissionCondition) { - throw new CommandException("You are not permitted to do that. Are you in the right mode?", e, null); - } + public void convert(IllegalArgumentException e) throws CommandException { + throw new CommandException(e.getMessage(), e, null); } } From c95fc06b828fb6be09e501542e1dfe63b624d937 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 23 Apr 2019 19:32:27 -0700 Subject: [PATCH 042/366] Port scripting commands --- .../worldedit/command/ScriptingCommands.java | 61 ++++++++++--------- .../platform/PlatformCommandMananger.java | 8 ++- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java index d09c76c39..e60a3db51 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ScriptingCommands.java @@ -19,23 +19,28 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; import java.io.File; +import java.util.List; +import java.util.stream.Stream; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; /** * Commands related to scripting. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class ScriptingCommands { private final WorldEdit worldEdit; @@ -51,43 +56,40 @@ public class ScriptingCommands { } @Command( - aliases = { "cs" }, - usage = " [args...]", - desc = "Execute a CraftScript", - min = 1, - max = -1 + name = "cs", + desc = "Execute a CraftScript" ) @CommandPermissions("worldedit.scripting.execute") @Logging(ALL) - public void execute(Player player, LocalSession session, CommandContext args) throws WorldEditException { - - String[] scriptArgs = args.getSlice(1); - String name = args.getString(0); - - if (!player.hasPermission("worldedit.scripting.execute." + name)) { + public void execute(Player player, LocalSession session, + @Arg(desc = "Filename of the CraftScript to load") + String filename, + @Arg(desc = "Arguments to the CraftScript", def = "", variable = true) + List args) throws WorldEditException { + if (!player.hasPermission("worldedit.scripting.execute." + filename)) { player.printError("You don't have permission to use that script."); return; } - session.setLastScript(name); + session.setLastScript(filename); File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir); - File f = worldEdit.getSafeOpenFile(player, dir, name, "js", "js"); + File f = worldEdit.getSafeOpenFile(player, dir, filename, "js", "js"); - worldEdit.runScript(player, f, scriptArgs); + worldEdit.runScript(player, f, Stream.concat(Stream.of(filename), args.stream()) + .toArray(String[]::new)); } @Command( - aliases = { ".s" }, - usage = "[args...]", - desc = "Execute last CraftScript", - min = 0, - max = -1 + name = ".s", + desc = "Execute last CraftScript" ) @CommandPermissions("worldedit.scripting.execute") @Logging(ALL) - public void executeLast(Player player, LocalSession session, CommandContext args) throws WorldEditException { - + public void executeLast(Player player, LocalSession session, + @Arg(desc = "Arguments to the CraftScript", def = "", variable = true) + List args) throws WorldEditException { + String lastScript = session.getLastScript(); if (!player.hasPermission("worldedit.scripting.execute." + lastScript)) { @@ -100,11 +102,10 @@ public class ScriptingCommands { return; } - String[] scriptArgs = args.getSlice(0); - File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir); File f = worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js"); - worldEdit.runScript(player, f, scriptArgs); + worldEdit.runScript(player, f, Stream.concat(Stream.of(lastScript), args.stream()) + .toArray(String[]::new)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 7dd59b9f2..a0a94591d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -46,6 +46,8 @@ import com.sk89q.worldedit.command.RegionCommands; import com.sk89q.worldedit.command.RegionCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; +import com.sk89q.worldedit.command.ScriptingCommands; +import com.sk89q.worldedit.command.ScriptingCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; import com.sk89q.worldedit.command.argument.DirectionConverter; @@ -298,13 +300,17 @@ public final class PlatformCommandMananger { RegionCommandsRegistration.builder(), new RegionCommands() ); + register( + commandManager, + ScriptingCommandsRegistration.builder(), + new ScriptingCommands(worldEdit) + ); // Unported commands are below. Delete once they're added to the main manager above. /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new ScriptingCommands(worldEdit)) .registerMethods(new SelectionCommands(worldEdit)) .registerMethods(new SnapshotUtilCommands(worldEdit)) .registerMethods(new ToolUtilCommands(worldEdit)) From e07e0d10b0a7d3f7219c5407051fad522b09e82b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 23 Apr 2019 22:58:30 -0700 Subject: [PATCH 043/366] Port selection commands --- .../worldedit/command/SelectionCommands.java | 562 +++++++----------- .../CommaSeparatedValuesConverter.java | 3 +- .../command/argument/DirectionConverter.java | 25 +- .../command/argument/EnumConverter.java | 52 ++ .../command/argument/ExpandAmount.java | 32 + .../argument/ExpandAmountConverter.java | 48 ++ .../command/argument/SelectorChoice.java | 14 + .../command/argument/VectorConverter.java | 109 ++++ .../platform/PlatformCommandMananger.java | 14 +- .../internal/annotation/MultiDirection.java | 37 ++ 10 files changed, 540 insertions(+), 356 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/MultiDirection.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index c79ec4fec..e705930a6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -19,18 +19,15 @@ package com.sk89q.worldedit.command; -import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; -import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.command.argument.ExpandAmount; +import com.sk89q.worldedit.command.argument.SelectorChoice; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.ParserContext; @@ -39,6 +36,8 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.block.BlockDistributionCounter; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.annotation.MultiDirection; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; @@ -64,44 +63,43 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.storage.ChunkStore; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.stream.Stream; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; /** * Selection commands. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class SelectionCommands { private final WorldEdit we; - + public SelectionCommands(WorldEdit we) { this.we = we; } @Command( - aliases = { "/pos1" }, - usage = "[coordinates]", - desc = "Set position 1", - min = 0, - max = 1 + name = "/pos1", + desc = "Set position 1" ) @Logging(POSITION) @CommandPermissions("worldedit.selection.pos") - public void pos1(Player player, LocalSession session, CommandContext args) throws WorldEditException { - + public void pos1(Player player, LocalSession session, + @Arg(desc = "Coordinates to set position 1 to", def = "") + BlockVector3 coordinates) throws WorldEditException { Location pos; - - if (args.argsLength() == 1) { - if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) { - String[] coords = args.getString(0).split(","); - pos = new Location(player.getWorld(), Integer.parseInt(coords[0]), Integer.parseInt(coords[1]), Integer.parseInt(coords[2])); - } else { - player.printError("Invalid coordinates " + args.getString(0)); - return; - } + if (coordinates != null) { + pos = new Location(player.getWorld(), coordinates.toVector3()); } else { pos = player.getBlockIn(); } @@ -116,27 +114,17 @@ public class SelectionCommands { } @Command( - aliases = { "/pos2" }, - usage = "[coordinates]", - desc = "Set position 2", - min = 0, - max = 1 + name = "/pos2", + desc = "Set position 2" ) @Logging(POSITION) @CommandPermissions("worldedit.selection.pos") - public void pos2(Player player, LocalSession session, CommandContext args) throws WorldEditException { - + public void pos2(Player player, LocalSession session, + @Arg(desc = "Coordinates to set position 2 to", def = "") + BlockVector3 coordinates) throws WorldEditException { Location pos; - if (args.argsLength() == 1) { - if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) { - String[] coords = args.getString(0).split(","); - pos = new Location(player.getWorld(), Integer.parseInt(coords[0]), - Integer.parseInt(coords[1]), - Integer.parseInt(coords[2])); - } else { - player.printError("Invalid coordinates " + args.getString(0)); - return; - } + if (coordinates != null) { + pos = new Location(player.getWorld(), coordinates.toVector3()); } else { pos = player.getBlockIn(); } @@ -151,11 +139,8 @@ public class SelectionCommands { } @Command( - aliases = { "/hpos1" }, - usage = "", - desc = "Set position 1 to targeted block", - min = 0, - max = 0 + name = "/hpos1", + desc = "Set position 1 to targeted block" ) @CommandPermissions("worldedit.selection.hpos") public void hpos1(Player player, LocalSession session) throws WorldEditException { @@ -176,11 +161,8 @@ public class SelectionCommands { } @Command( - aliases = { "/hpos2" }, - usage = "", - desc = "Set position 2 to targeted block", - min = 0, - max = 0 + name = "/hpos2", + desc = "Set position 2 to targeted block" ) @CommandPermissions("worldedit.selection.hpos") public void hpos2(Player player, LocalSession session) throws WorldEditException { @@ -201,28 +183,22 @@ public class SelectionCommands { } @Command( - aliases = { "/chunk" }, - usage = "[x,z coordinates]", - flags = "sc", - desc = "Set the selection to your current chunk.", - help = - "Set the selection to the chunk you are currently in.\n" + - "With the -s flag, your current selection is expanded\n" + - "to encompass all chunks that are part of it.\n\n" + - "Specifying coordinates will use those instead of your\n"+ - "current position. Use -c to specify chunk coordinates,\n" + - "otherwise full coordinates will be implied.\n" + - "(for example, the coordinates 5,5 are the same as -c 0,0)", - min = 0, - max = 1 + name = "/chunk", + desc = "Set the selection to your current chunk." ) @Logging(POSITION) @CommandPermissions("worldedit.selection.chunk") - public void chunk(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void chunk(Player player, LocalSession session, + @Arg(desc = "The chunk to select", def = "") + BlockVector2 coordinates, + @Switch(name = 's', desc = "Expand your selection to encompass all chunks that are part of it") + boolean expandSelection, + @Switch(name = 'c', desc = "Use chunk coordinates instead of block coordinates") + boolean useChunkCoordinates) throws WorldEditException { final BlockVector3 min; final BlockVector3 max; final World world = player.getWorld(); - if (args.hasFlag('s')) { + if (expandSelection) { Region region = session.getSelection(world); final BlockVector2 min2D = ChunkStore.toChunk(region.getMinimumPoint()); @@ -236,16 +212,11 @@ public class SelectionCommands { + max2D.getBlockX() + ", " + max2D.getBlockZ() + ")"); } else { final BlockVector2 min2D; - if (args.argsLength() == 1) { + if (coordinates != null) { // coords specified - String[] coords = args.getString(0).split(","); - if (coords.length != 2) { - throw new InsufficientArgumentsException("Invalid coordinates specified."); - } - int x = Integer.parseInt(coords[0]); - int z = Integer.parseInt(coords[1]); - BlockVector2 pos = BlockVector2.at(x, z); - min2D = (args.hasFlag('c')) ? pos : ChunkStore.toChunk(pos.toBlockVector3()); + min2D = useChunkCoordinates + ? coordinates + : ChunkStore.toChunk(coordinates.toBlockVector3()); } else { // use player loc min2D = ChunkStore.toChunk(player.getBlockIn().toVector().toBlockPoint()); @@ -273,29 +244,21 @@ public class SelectionCommands { } @Command( - aliases = { "/wand" }, - usage = "", - desc = "Get the wand object", - min = 0, - max = 0 + name = "/wand", + desc = "Get the wand object" ) @CommandPermissions("worldedit.wand") public void wand(Player player) throws WorldEditException { - player.giveItem(new BaseItemStack(ItemTypes.get(we.getConfiguration().wandItem), 1)); player.print("Left click: select pos #1; Right click: select pos #2"); } @Command( - aliases = { "toggleeditwand" }, - usage = "", - desc = "Toggle functionality of the edit wand", - min = 0, - max = 0 + name = "toggleeditwand", + desc = "Toggle functionality of the edit wand" ) @CommandPermissions("worldedit.wand.toggle") - public void toggleWand(Player player, LocalSession session, CommandContext args) throws WorldEditException { - + public void toggleWand(Player player, LocalSession session) throws WorldEditException { session.setToolControl(!session.isToolControlEnabled()); if (session.isToolControlEnabled()) { @@ -306,20 +269,23 @@ public class SelectionCommands { } @Command( - aliases = { "/expand" }, - usage = " [reverse-amount] ", - desc = "Expand the selection area", - min = 1, - max = 3 + name = "/expand", + desc = "Expand the selection area" ) @Logging(REGION) @CommandPermissions("worldedit.selection.expand") - public void expand(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void expand(Player player, LocalSession session, + @Arg(desc = "Amount to expand the selection by, can be `vert` to expand to the whole vertical column") + ExpandAmount amount, + @Arg(desc = "Amount to expand the selection by in the other direction", def = "0") + int reverseAmount, + @Arg(desc = "Direction to expand", def = Direction.AIM) + @MultiDirection + List direction) throws WorldEditException { // Special syntax (//expand vert) to expand the selection between // sky and bedrock. - if (args.getString(0).equalsIgnoreCase("vert") - || args.getString(0).equalsIgnoreCase("vertical")) { + if (amount.isVert()) { Region region = session.getSelection(player.getWorld()); try { int oldSize = region.getArea(); @@ -338,134 +304,56 @@ public class SelectionCommands { return; } - List dirs = new ArrayList<>(); - int change = args.getInteger(0); - int reverseChange = 0; - - switch (args.argsLength()) { - case 2: - // Either a reverse amount or a direction - try { - reverseChange = args.getInteger(1); - dirs.add(we.getDirection(player, "me")); - } catch (NumberFormatException e) { - if (args.getString(1).contains(",")) { - String[] split = args.getString(1).split(","); - for (String s : split) { - dirs.add(we.getDirection(player, s.toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, args.getString(1).toLowerCase())); - } - } - break; - - case 3: - // Both reverse amount and direction - reverseChange = args.getInteger(1); - if (args.getString(2).contains(",")) { - String[] split = args.getString(2).split(","); - for (String s : split) { - dirs.add(we.getDirection(player, s.toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, args.getString(2).toLowerCase())); - } - break; - - default: - dirs.add(we.getDirection(player, "me")); - break; - - } - Region region = session.getSelection(player.getWorld()); int oldSize = region.getArea(); - if (reverseChange == 0) { - for (BlockVector3 dir : dirs) { - region.expand(dir.multiply(change)); + if (reverseAmount == 0) { + for (BlockVector3 dir : direction) { + region.expand(dir.multiply(amount.getAmount())); } } else { - for (BlockVector3 dir : dirs) { - region.expand(dir.multiply(change), dir.multiply(-reverseChange)); + for (BlockVector3 dir : direction) { + region.expand(dir.multiply(amount.getAmount()), dir.multiply(-reverseAmount)); } } session.getRegionSelector(player.getWorld()).learnChanges(); int newSize = region.getArea(); - + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - player.print("Region expanded " + (newSize - oldSize) + " blocks."); + player.print("Region expanded " + (newSize - oldSize) + " block(s)."); } @Command( - aliases = { "/contract" }, - usage = " [reverse-amount] [direction]", - desc = "Contract the selection area", - min = 1, - max = 3 + name = "/contract", + desc = "Contract the selection area" ) @Logging(REGION) @CommandPermissions("worldedit.selection.contract") - public void contract(Player player, LocalSession session, CommandContext args) throws WorldEditException { - - List dirs = new ArrayList<>(); - int change = args.getInteger(0); - int reverseChange = 0; - - switch (args.argsLength()) { - case 2: - // Either a reverse amount or a direction - try { - reverseChange = args.getInteger(1); - dirs.add(we.getDirection(player, "me")); - } catch (NumberFormatException e) { - if (args.getString(1).contains(",")) { - String[] split = args.getString(1).split(","); - for (String s : split) { - dirs.add(we.getDirection(player, s.toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, args.getString(1).toLowerCase())); - } - } - break; - - case 3: - // Both reverse amount and direction - reverseChange = args.getInteger(1); - if (args.getString(2).contains(",")) { - String[] split = args.getString(2).split(","); - for (String s : split) { - dirs.add(we.getDirection(player, s.toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, args.getString(2).toLowerCase())); - } - break; - - default: - dirs.add(we.getDirection(player, "me")); - break; - } - + public void contract(Player player, LocalSession session, + @Arg(desc = "Amount to contract the selection by") + int amount, + @Arg(desc = "Amount to contract the selection by in the other direction", def = "0") + int reverseAmount, + @Arg(desc = "Direction to contract", def = Direction.AIM) + @MultiDirection + List direction) throws WorldEditException { try { Region region = session.getSelection(player.getWorld()); int oldSize = region.getArea(); - if (reverseChange == 0) { - for (BlockVector3 dir : dirs) { - region.contract(dir.multiply(change)); + if (reverseAmount == 0) { + for (BlockVector3 dir : direction) { + region.contract(dir.multiply(amount)); } } else { - for (BlockVector3 dir : dirs) { - region.contract(dir.multiply(change), dir.multiply(-reverseChange)); + for (BlockVector3 dir : direction) { + region.contract(dir.multiply(amount), dir.multiply(-reverseAmount)); } } session.getRegionSelector(player.getWorld()).learnChanges(); int newSize = region.getArea(); - + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); @@ -476,35 +364,22 @@ public class SelectionCommands { } @Command( - aliases = { "/shift" }, - usage = " [direction]", - desc = "Shift the selection area", - min = 1, - max = 2 + name = "/shift", + desc = "Shift the selection area" ) @Logging(REGION) @CommandPermissions("worldedit.selection.shift") - public void shift(Player player, LocalSession session, CommandContext args) throws WorldEditException { - - List dirs = new ArrayList<>(); - int change = args.getInteger(0); - if (args.argsLength() == 2) { - if (args.getString(1).contains(",")) { - for (String s : args.getString(1).split(",")) { - dirs.add(we.getDirection(player, s.toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, args.getString(1).toLowerCase())); - } - } else { - dirs.add(we.getDirection(player, "me")); - } - + public void shift(Player player, LocalSession session, + @Arg(desc = "Amount to shift the selection by") + int amount, + @Arg(desc = "Direction to contract", def = Direction.AIM) + @MultiDirection + List direction) throws WorldEditException { try { Region region = session.getSelection(player.getWorld()); - for (BlockVector3 dir : dirs) { - region.shift(dir.multiply(change)); + for (BlockVector3 dir : direction) { + region.shift(dir.multiply(amount)); } session.getRegionSelector(player.getWorld()).learnChanges(); @@ -518,81 +393,72 @@ public class SelectionCommands { } @Command( - aliases = { "/outset" }, - usage = "", - desc = "Outset the selection area", - help = - "Expands the selection by the given amount in all directions.\n" + - "Flags:\n" + - " -h only expand horizontally\n" + - " -v only expand vertically\n", - flags = "hv", - min = 1, - max = 1 + name = "/outset", + desc = "Outset the selection area" ) @Logging(REGION) @CommandPermissions("worldedit.selection.outset") - public void outset(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void outset(Player player, LocalSession session, + @Arg(desc = "Amount to expand the selection by in all directions") + int amount, + @Switch(name = 'h', desc = "Only expand horizontally") + boolean onlyHorizontal, + @Switch(name = 'v', desc = "Only expand vertically") + boolean onlyVertical) throws WorldEditException { Region region = session.getSelection(player.getWorld()); - region.expand(getChangesForEachDir(args)); + region.expand(getChangesForEachDir(amount, onlyHorizontal, onlyVertical)); session.getRegionSelector(player.getWorld()).learnChanges(); session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); player.print("Region outset."); } @Command( - aliases = { "/inset" }, - usage = "", - desc = "Inset the selection area", - help = - "Contracts the selection by the given amount in all directions.\n" + - "Flags:\n" + - " -h only contract horizontally\n" + - " -v only contract vertically\n", - flags = "hv", - min = 1, - max = 1 + name = "/inset", + desc = "Inset the selection area" ) @Logging(REGION) @CommandPermissions("worldedit.selection.inset") - public void inset(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void inset(Player player, LocalSession session, + @Arg(desc = "Amount to contract the selection by in all directions") + int amount, + @Switch(name = 'h', desc = "Only contract horizontally") + boolean onlyHorizontal, + @Switch(name = 'v', desc = "Only contract vertically") + boolean onlyVertical) throws WorldEditException { Region region = session.getSelection(player.getWorld()); - region.contract(getChangesForEachDir(args)); + region.contract(getChangesForEachDir(amount, onlyHorizontal, onlyVertical)); session.getRegionSelector(player.getWorld()).learnChanges(); session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); player.print("Region inset."); } - private BlockVector3[] getChangesForEachDir(CommandContext args) { - List changes = new ArrayList<>(6); - int change = args.getInteger(0); + private BlockVector3[] getChangesForEachDir(int amount, boolean onlyHorizontal, boolean onlyVertical) { + Stream.Builder changes = Stream.builder(); - if (!args.hasFlag('h')) { - changes.add((BlockVector3.UNIT_Y).multiply(change)); - changes.add((BlockVector3.UNIT_MINUS_Y).multiply(change)); + if (!onlyHorizontal) { + changes.add(BlockVector3.UNIT_Y); + changes.add(BlockVector3.UNIT_MINUS_Y); } - if (!args.hasFlag('v')) { - changes.add((BlockVector3.UNIT_X).multiply(change)); - changes.add((BlockVector3.UNIT_MINUS_X).multiply(change)); - changes.add((BlockVector3.UNIT_Z).multiply(change)); - changes.add((BlockVector3.UNIT_MINUS_Z).multiply(change)); + if (!onlyVertical) { + changes.add(BlockVector3.UNIT_X); + changes.add(BlockVector3.UNIT_MINUS_X); + changes.add(BlockVector3.UNIT_Z); + changes.add(BlockVector3.UNIT_MINUS_Z); } - return changes.toArray(new BlockVector3[0]); + return changes.build().map(v -> v.multiply(amount)).toArray(BlockVector3[]::new); } @Command( - aliases = { "/size" }, - flags = "c", - usage = "", - desc = "Get information about the selection", - min = 0, - max = 0 + name = "/size", + desc = "Get information about the selection" ) @CommandPermissions("worldedit.selection.size") - public void size(Player player, LocalSession session, CommandContext args) throws WorldEditException { - if (args.hasFlag('c')) { + public void size(Player player, LocalSession session, + @Switch(name = 'c', desc = "Get clipboard info instead") + boolean clipboardInfo) throws WorldEditException { + if (clipboardInfo) { ClipboardHolder holder = session.getClipboard(); Clipboard clipboard = holder.getClipboard(); Region region = clipboard.getRegion(); @@ -602,7 +468,7 @@ public class SelectionCommands { player.print("Cuboid dimensions (max - min): " + size); player.print("Offset: " + origin); player.print("Cuboid distance: " + size.distance(BlockVector3.ONE)); - player.print("# of blocks: " + (int) (size.getX() * size.getY() * size.getZ())); + player.print("# of blocks: " + (size.getX() * size.getY() * size.getZ())); return; } @@ -626,48 +492,41 @@ public class SelectionCommands { @Command( - aliases = { "/count" }, - usage = "", - flags = "f", - desc = "Counts the number of a certain type of block", - min = 1, - max = 1 + name = "/count", + desc = "Counts the number of a certain type of block" ) @CommandPermissions("worldedit.analysis.count") - public void count(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - + public void count(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The block type(s) to count") + String blocks, + @Switch(name = 'f', desc = "Fuzzy, match states using a wildcard") + boolean fuzzy) throws WorldEditException { ParserContext context = new ParserContext(); context.setActor(player); context.setExtent(player.getExtent()); context.setWorld(player.getWorld()); context.setSession(session); context.setRestricted(false); - context.setPreferringWildcard(args.hasFlag('f')); + context.setPreferringWildcard(fuzzy); - Set searchBlocks = we.getBlockFactory().parseFromListInput(args.getString(0), context); + Set searchBlocks = we.getBlockFactory().parseFromListInput(blocks, context); int count = editSession.countBlocks(session.getSelection(player.getWorld()), searchBlocks); player.print("Counted: " + count); } @Command( - aliases = { "/distr" }, - usage = "", - desc = "Get the distribution of blocks in the selection", - help = - "Gets the distribution of blocks in the selection.\n" + - "The -c flag gets the distribution of your clipboard.\n" + - "The -d flag separates blocks by state", - flags = "cd", - min = 0, - max = 0 + name = "/distr", + desc = "Get the distribution of blocks in the selection" ) @CommandPermissions("worldedit.analysis.distr") - public void distr(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException, CommandException { - - boolean separateStates = args.hasFlag('d'); + public void distr(Player player, LocalSession session, EditSession editSession, + @Switch(name = 'c', desc = "Get the distribution of the clipboard instead") + boolean clipboardDistr, + @Switch(name = 'd', desc = "Separate blocks by state") + boolean separateStates) throws WorldEditException { List> distribution; - if (args.hasFlag('c')) { + if (clipboardDistr) { Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing BlockDistributionCounter count = new BlockDistributionCounter(clipboard, separateStates); RegionVisitor visitor = new RegionVisitor(clipboard.getRegion(), count); @@ -707,73 +566,86 @@ public class SelectionCommands { } @Command( - aliases = { "/sel", ";", "/desel", "/deselect" }, - flags = "d", - usage = "[cuboid|extend|poly|ellipsoid|sphere|cyl|convex]", - desc = "Choose a region selector", - min = 0, - max = 1 + name = "/sel", + aliases = { ";", "/desel", "/deselect" }, + desc = "Choose a region selector" ) - public void select(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void select(Player player, LocalSession session, + @Arg(desc = "Selector to switch to", def = "") + SelectorChoice selector, + @Switch(name = 'd', desc = "Set default selector") + boolean setDefaultSelector) throws WorldEditException { final World world = player.getWorld(); - if (args.argsLength() == 0) { + if (selector == null) { session.getRegionSelector(world).clear(); session.dispatchCUISelection(player); player.print("Selection cleared."); return; } - final String typeName = args.getString(0); final RegionSelector oldSelector = session.getRegionSelector(world); - final RegionSelector selector; - if (typeName.equalsIgnoreCase("cuboid")) { - selector = new CuboidRegionSelector(oldSelector); - player.print("Cuboid: left click for point 1, right click for point 2"); - } else if (typeName.equalsIgnoreCase("extend")) { - selector = new ExtendingCuboidRegionSelector(oldSelector); - player.print("Cuboid: left click for a starting point, right click to extend"); - } else if (typeName.equalsIgnoreCase("poly")) { - selector = new Polygonal2DRegionSelector(oldSelector); - player.print("2D polygon selector: Left/right click to add a point."); - Optional limit = ActorSelectorLimits.forActor(player).getPolygonVertexLimit(); - limit.ifPresent(integer -> player.print(integer + " points maximum.")); - } else if (typeName.equalsIgnoreCase("ellipsoid")) { - selector = new EllipsoidRegionSelector(oldSelector); - player.print("Ellipsoid selector: left click=center, right click to extend"); - } else if (typeName.equalsIgnoreCase("sphere")) { - selector = new SphereRegionSelector(oldSelector); - player.print("Sphere selector: left click=center, right click to set radius"); - } else if (typeName.equalsIgnoreCase("cyl")) { - selector = new CylinderRegionSelector(oldSelector); - player.print("Cylindrical selector: Left click=center, right click to extend."); - } else if (typeName.equalsIgnoreCase("convex") || typeName.equalsIgnoreCase("hull") || typeName.equalsIgnoreCase("polyhedron")) { - selector = new ConvexPolyhedralRegionSelector(oldSelector); - player.print("Convex polyhedral selector: Left click=First vertex, right click to add more."); - Optional limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit(); - limit.ifPresent(integer -> player.print(integer + " points maximum.")); - } else { - CommandListBox box = new CommandListBox("Selection modes"); - StyledFragment contents = box.getContents(); - StyledFragment tip = contents.createFragment(Style.RED); - tip.append("Select one of the modes below:").newLine(); + final RegionSelector newSelector; + switch (selector) { + case CUBOID: + newSelector = new CuboidRegionSelector(oldSelector); + player.print("Cuboid: left click for point 1, right click for point 2"); + break; + case EXTEND: + newSelector = new ExtendingCuboidRegionSelector(oldSelector); + player.print("Cuboid: left click for a starting point, right click to extend"); + break; + case POLY: { + newSelector = new Polygonal2DRegionSelector(oldSelector); + player.print("2D polygon selector: Left/right click to add a point."); + Optional limit = ActorSelectorLimits.forActor(player).getPolygonVertexLimit(); + limit.ifPresent(integer -> player.print(integer + " points maximum.")); + break; + } + case ELLIPSOID: + newSelector = new EllipsoidRegionSelector(oldSelector); + player.print("Ellipsoid selector: left click=center, right click to extend"); + break; + case SPHERE: + newSelector = new SphereRegionSelector(oldSelector); + player.print("Sphere selector: left click=center, right click to set radius"); + break; + case CYL: + newSelector = new CylinderRegionSelector(oldSelector); + player.print("Cylindrical selector: Left click=center, right click to extend."); + break; + case CONVEX: + case HULL: + case POLYHEDRON: { + newSelector = new ConvexPolyhedralRegionSelector(oldSelector); + player.print("Convex polyhedral selector: Left click=First vertex, right click to add more."); + Optional limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit(); + limit.ifPresent(integer -> player.print(integer + " points maximum.")); + break; + } + case UNKNOWN: + default: + CommandListBox box = new CommandListBox("Selection modes"); + StyledFragment contents = box.getContents(); + StyledFragment tip = contents.createFragment(Style.RED); + tip.append("Select one of the modes below:").newLine(); - box.appendCommand("cuboid", "Select two corners of a cuboid"); - box.appendCommand("extend", "Fast cuboid selection mode"); - box.appendCommand("poly", "Select a 2D polygon with height"); - box.appendCommand("ellipsoid", "Select an ellipsoid"); - box.appendCommand("sphere", "Select a sphere"); - box.appendCommand("cyl", "Select a cylinder"); - box.appendCommand("convex", "Select a convex polyhedral"); + box.appendCommand("cuboid", "Select two corners of a cuboid"); + box.appendCommand("extend", "Fast cuboid selection mode"); + box.appendCommand("poly", "Select a 2D polygon with height"); + box.appendCommand("ellipsoid", "Select an ellipsoid"); + box.appendCommand("sphere", "Select a sphere"); + box.appendCommand("cyl", "Select a cylinder"); + box.appendCommand("convex", "Select a convex polyhedral"); - player.printRaw(ColorCodeBuilder.asColorCodes(box)); - return; + player.printRaw(ColorCodeBuilder.asColorCodes(box)); + return; } - if (args.hasFlag('d')) { + if (setDefaultSelector) { RegionSelectorType found = null; for (RegionSelectorType type : RegionSelectorType.values()) { - if (type.getSelectorClass() == selector.getClass()) { + if (type.getSelectorClass() == newSelector.getClass()) { found = type; break; } @@ -787,7 +659,7 @@ public class SelectionCommands { } } - session.setRegionSelector(world, selector); + session.setRegionSelector(world, newSelector); session.dispatchCUISelection(player); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java index d2947a44a..70db3963f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java @@ -59,9 +59,8 @@ public class CommaSeparatedValuesConverter implements ArgumentConverter { if (maximum > -1) { result.append("up to ").append(maximum).append(' '); } - result.append("comma separated values of ") + result.append("comma separated values of: ") .append(delegate.describeAcceptableArguments()); - result.setCharAt(0, Character.toUpperCase(result.charAt(0))); return result.toString(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java index f454191da..092b7bf5d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.UnknownDirectionException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.annotation.MultiDirection; import com.sk89q.worldedit.math.BlockVector3; import org.enginehub.piston.CommandManager; import org.enginehub.piston.converter.ArgumentConverter; @@ -46,15 +47,23 @@ public class DirectionConverter implements ArgumentConverter { return new AutoAnnotation_DirectionConverter_direction(includeDiagonals); } + @AutoAnnotation + private static MultiDirection multiDirection(boolean includeDiagonals) { + return new AutoAnnotation_DirectionConverter_multiDirection(includeDiagonals); + } + public static void register(WorldEdit worldEdit, CommandManager commandManager) { - commandManager.registerConverter( - Key.of(BlockVector3.class, direction(false)), - new DirectionConverter(worldEdit, false) - ); - commandManager.registerConverter( - Key.of(BlockVector3.class, direction(true)), - new DirectionConverter(worldEdit, true) - ); + for (boolean includeDiagonals : new boolean[] { false, true }) { + DirectionConverter directionConverter = new DirectionConverter(worldEdit, includeDiagonals); + commandManager.registerConverter( + Key.of(BlockVector3.class, direction(includeDiagonals)), + directionConverter + ); + commandManager.registerConverter( + Key.of(BlockVector3.class, multiDirection(includeDiagonals)), + CommaSeparatedValuesConverter.wrap(directionConverter) + ); + } } private static final ImmutableSet NON_DIAGONALS = ImmutableSet.of( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java new file mode 100644 index 000000000..353a46a77 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java @@ -0,0 +1,52 @@ +package com.sk89q.worldedit.command.argument; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedMap; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import javax.annotation.Nullable; +import java.util.EnumSet; + +public class EnumConverter> implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(SelectorChoice.class), + new EnumConverter<>(SelectorChoice.class, SelectorChoice.UNKNOWN)); + } + + private final ImmutableMap map; + @Nullable + private final E unknownValue; + + private EnumConverter(Class enumClass, @Nullable E unknownValue) { + ImmutableSortedMap.Builder map = ImmutableSortedMap.orderedBy(String.CASE_INSENSITIVE_ORDER); + EnumSet validValues = EnumSet.allOf(enumClass); + if (unknownValue != null) { + validValues.remove(unknownValue); + } + for (E e : validValues) { + map.put(e.name(), e); + } + this.map = map.build(); + this.unknownValue = unknownValue; + } + + @Override + public String describeAcceptableArguments() { + return String.join("|", map.keySet()); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + E result = map.getOrDefault(argument, unknownValue); + return result == null + ? FailedConversion.from(new IllegalArgumentException("Not a valid choice: " + argument)) + : SuccessfulConversion.fromSingle(result); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java new file mode 100644 index 000000000..d567c3d19 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java @@ -0,0 +1,32 @@ +package com.sk89q.worldedit.command.argument; + +import javax.annotation.Nullable; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class ExpandAmount { + + public static ExpandAmount vert() { + return new ExpandAmount(null); + } + + public static ExpandAmount from(int amount) { + return new ExpandAmount(amount); + } + + @Nullable + private final Integer amount; + + private ExpandAmount(@Nullable Integer amount) { + this.amount = amount; + } + + public boolean isVert() { + return amount == null; + } + + public int getAmount() { + return checkNotNull(amount, "This amount is vertical, i.e. undefined"); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java new file mode 100644 index 000000000..4c6e64c77 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java @@ -0,0 +1,48 @@ +package com.sk89q.worldedit.command.argument; + +import com.google.common.reflect.TypeToken; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ArgumentConverters; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ExpandAmountConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(ExpandAmount.class), new ExpandAmountConverter()); + } + + private final ArgumentConverter integerConverter = + ArgumentConverters.get(TypeToken.of(int.class)); + + private ExpandAmountConverter() { + } + + @Override + public String describeAcceptableArguments() { + return "`vert` or " + integerConverter.describeAcceptableArguments(); + } + + @Override + public List getSuggestions(String input) { + return Stream.concat(Stream.of("vert"), integerConverter.getSuggestions(input).stream()) + .filter(x -> x.startsWith(input)) + .collect(Collectors.toList()); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + if (argument.equalsIgnoreCase("vert") + || argument.equalsIgnoreCase("vertical")) { + return SuccessfulConversion.fromSingle(ExpandAmount.vert()); + } + return integerConverter.convert(argument, context).mapSingle(ExpandAmount::from); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java new file mode 100644 index 000000000..8aa63e6e0 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java @@ -0,0 +1,14 @@ +package com.sk89q.worldedit.command.argument; + +public enum SelectorChoice { + CUBOID, + EXTEND, + POLY, + ELLIPSOID, + SPHERE, + CYL, + CONVEX, + HULL, + POLYHEDRON, + UNKNOWN +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java new file mode 100644 index 000000000..fda47dd0f --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java @@ -0,0 +1,109 @@ +/* + * 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.command.argument; + +import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector2; +import com.sk89q.worldedit.math.Vector3; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ArgumentConverters; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SimpleArgumentConverter; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import java.util.function.Function; + +public class VectorConverter implements ArgumentConverter { + public static void register(CommandManager commandManager) { + CommaSeparatedValuesConverter intConverter = CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(int.class))); + CommaSeparatedValuesConverter doubleConverter = CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(double.class))); + commandManager.registerConverter(Key.of(BlockVector2.class), + new VectorConverter<>( + intConverter, + 2, + cmps -> BlockVector2.at(cmps.get(0), cmps.get(1)), + "block vector with x and z" + )); + commandManager.registerConverter(Key.of(Vector2.class), + new VectorConverter<>( + doubleConverter, + 3, + cmps -> Vector2.at(cmps.get(0), cmps.get(1)), + "vector with x and z" + )); + commandManager.registerConverter(Key.of(BlockVector3.class), + new VectorConverter<>( + intConverter, + 2, + cmps -> BlockVector3.at(cmps.get(0), cmps.get(1), cmps.get(2)), + "block vector with x, y, and z" + )); + commandManager.registerConverter(Key.of(Vector3.class), + new VectorConverter<>( + doubleConverter, + 3, + cmps -> Vector3.at(cmps.get(0), cmps.get(1), cmps.get(2)), + "vector with x, y, and z" + )); + } + + private final ArgumentConverter componentConverter; + private final int componentCount; + private final Function, T> vectorConstructor; + private final String acceptableArguments; + + + private VectorConverter(ArgumentConverter componentConverter, + int componentCount, + Function, T> vectorConstructor, + String acceptableArguments) { + this.componentConverter = componentConverter; + this.componentCount = componentCount; + this.vectorConstructor = vectorConstructor; + this.acceptableArguments = acceptableArguments; + } + + @Override + public String describeAcceptableArguments() { + return "any " + acceptableArguments; + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + ConversionResult components = componentConverter.convert(argument, context); + if (!components.isSuccessful()) { + return components.failureAsAny(); + } + if (components.get().size() != componentCount) { + return FailedConversion.from(new IllegalArgumentException( + "Must have exactly " + componentCount + " vector components")); + } + T vector = vectorConstructor.apply(ImmutableList.copyOf(components.get())); + return SuccessfulConversion.fromSingle(vector); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index a0a94591d..037617ab3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -48,11 +48,16 @@ import com.sk89q.worldedit.command.SchematicCommands; import com.sk89q.worldedit.command.SchematicCommandsRegistration; import com.sk89q.worldedit.command.ScriptingCommands; import com.sk89q.worldedit.command.ScriptingCommandsRegistration; +import com.sk89q.worldedit.command.SelectionCommands; +import com.sk89q.worldedit.command.SelectionCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; import com.sk89q.worldedit.command.argument.DirectionConverter; +import com.sk89q.worldedit.command.argument.EnumConverter; +import com.sk89q.worldedit.command.argument.ExpandAmountConverter; import com.sk89q.worldedit.command.argument.MaskConverter; import com.sk89q.worldedit.command.argument.PatternConverter; +import com.sk89q.worldedit.command.argument.VectorConverter; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Entity; @@ -193,6 +198,9 @@ public final class PlatformCommandMananger { ), count) ); } + VectorConverter.register(commandManager); + EnumConverter.register(commandManager); + ExpandAmountConverter.register(commandManager); } private void registerAlwaysInjectedValues() { @@ -305,13 +313,17 @@ public final class PlatformCommandMananger { ScriptingCommandsRegistration.builder(), new ScriptingCommands(worldEdit) ); + register( + commandManager, + SelectionCommandsRegistration.builder(), + new SelectionCommands(worldEdit) + ); // Unported commands are below. Delete once they're added to the main manager above. /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new SelectionCommands(worldEdit)) .registerMethods(new SnapshotUtilCommands(worldEdit)) .registerMethods(new ToolUtilCommands(worldEdit)) .registerMethods(new ToolCommands(worldEdit)) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/MultiDirection.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/MultiDirection.java new file mode 100644 index 000000000..efd1ba701 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/MultiDirection.java @@ -0,0 +1,37 @@ +/* + * 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.internal.annotation; + +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates a {@code List} parameter to inject multiple direction. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface MultiDirection { + boolean includeDiagonals() default false; +} From ea3605204c424ae896b68748f2dd531eaa30dd25 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 23 Apr 2019 22:59:11 -0700 Subject: [PATCH 044/366] Fix licenses --- .../command/argument/EnumConverter.java | 19 +++++++++++++++++++ .../command/argument/ExpandAmount.java | 19 +++++++++++++++++++ .../argument/ExpandAmountConverter.java | 19 +++++++++++++++++++ .../command/argument/SelectorChoice.java | 19 +++++++++++++++++++ 4 files changed, 76 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java index 353a46a77..a5fab7da3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java @@ -1,3 +1,22 @@ +/* + * 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.command.argument; import com.google.common.collect.ImmutableMap; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java index d567c3d19..062a330c9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java @@ -1,3 +1,22 @@ +/* + * 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.command.argument; import javax.annotation.Nullable; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java index 4c6e64c77..02ef20447 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java @@ -1,3 +1,22 @@ +/* + * 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.command.argument; import com.google.common.reflect.TypeToken; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java index 8aa63e6e0..c17c71601 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java @@ -1,3 +1,22 @@ +/* + * 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.command.argument; public enum SelectorChoice { From 2ea30dc70efb01065b80290bc199263ddce1494b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 23 Apr 2019 23:47:22 -0700 Subject: [PATCH 045/366] Port snapshot commands, update some time stuff to new time --- .../com/sk89q/worldedit/LocalSession.java | 12 +- .../worldedit/command/SnapshotCommands.java | 139 +++++++----------- .../command/SnapshotUtilCommands.java | 27 ++-- .../worldedit/command/WorldEditCommands.java | 23 +-- .../argument/ZonedDateTimeConverter.java | 40 +++++ .../platform/PlatformCommandMananger.java | 33 ++++- .../worldedit/world/snapshot/Snapshot.java | 8 +- .../world/snapshot/SnapshotRepository.java | 15 +- 8 files changed, 172 insertions(+), 125 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index bf15a504a..b0c1ebd45 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -52,6 +52,7 @@ import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.snapshot.Snapshot; import javax.annotation.Nullable; +import java.time.ZoneId; import java.util.Calendar; import java.util.HashMap; import java.util.LinkedList; @@ -91,7 +92,7 @@ public class LocalSession { private transient int cuiVersion = -1; private transient boolean fastMode = false; private transient Mask mask; - private transient TimeZone timezone = TimeZone.getDefault(); + private transient ZoneId timezone = ZoneId.systemDefault(); private transient BlockVector3 cuiTemporaryBlock; private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE; @@ -169,7 +170,7 @@ public class LocalSession { * * @return the timezone */ - public TimeZone getTimeZone() { + public ZoneId getTimeZone() { return timezone; } @@ -178,7 +179,7 @@ public class LocalSession { * * @param timezone the user's timezone */ - public void setTimezone(TimeZone timezone) { + public void setTimezone(ZoneId timezone) { checkNotNull(timezone); this.timezone = timezone; } @@ -849,9 +850,10 @@ public class LocalSession { public Calendar detectDate(String input) { checkNotNull(input); - Time.setTimeZone(getTimeZone()); + TimeZone tz = TimeZone.getTimeZone(getTimeZone()); + Time.setTimeZone(tz); Options opt = new com.sk89q.jchronic.Options(); - opt.setNow(Calendar.getInstance(getTimeZone())); + opt.setNow(Calendar.getInstance(tz)); Span date = Chronic.parse(input, opt); if (date == null) { return null; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java index 1c4987734..643b064b1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java @@ -21,32 +21,34 @@ package com.sk89q.worldedit.command; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException; import com.sk89q.worldedit.world.snapshot.Snapshot; import com.sk89q.worldedit.world.storage.MissingWorldException; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; import java.io.File; import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; /** * Snapshot commands. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class SnapshotCommands { - private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); - + private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z"); + private final WorldEdit we; public SnapshotCommands(WorldEdit we) { @@ -54,14 +56,13 @@ public class SnapshotCommands { } @Command( - aliases = { "list" }, - usage = "[num]", - desc = "List snapshots", - min = 0, - max = 1 + name = "list", + desc = "List snapshots" ) @CommandPermissions("worldedit.snapshots.list") - public void list(Player player, CommandContext args) throws WorldEditException { + public void list(Player player, + @Arg(desc = "# of snapshots to list", def = "5") + int num) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); @@ -75,7 +76,7 @@ public class SnapshotCommands { if (!snapshots.isEmpty()) { - int num = args.argsLength() > 0 ? Math.min(40, Math.max(5, args.getInteger(0))) : 5; + num = Math.min(40, Math.max(5, num)); player.print("Snapshots for world: '" + player.getWorld().getName() + "'"); for (byte i = 0; i < Math.min(num, snapshots.size()); i++) { @@ -104,14 +105,13 @@ public class SnapshotCommands { } @Command( - aliases = { "use" }, - usage = "", - desc = "Choose a snapshot to use", - min = 1, - max = 1 + name = "use", + desc = "Choose a snapshot to use" ) @CommandPermissions("worldedit.snapshots.restore") - public void use(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void use(Player player, LocalSession session, + @Arg(desc = "Snapeshot to use") + String name) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); @@ -120,8 +120,6 @@ public class SnapshotCommands { return; } - String name = args.getString(0); - // Want the latest snapshot? if (name.equalsIgnoreCase("latest")) { try { @@ -147,14 +145,13 @@ public class SnapshotCommands { } @Command( - aliases = { "sel" }, - usage = "", - desc = "Choose the snapshot based on the list id", - min = 1, - max = 1 + name = "sel", + desc = "Choose the snapshot based on the list id" ) @CommandPermissions("worldedit.snapshots.restore") - public void sel(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void sel(Player player, LocalSession session, + @Arg(desc = "The list ID to select") + int index) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { @@ -162,14 +159,6 @@ public class SnapshotCommands { return; } - int index = -1; - try { - index = Integer.parseInt(args.getString(0)); - } catch (NumberFormatException e) { - player.printError("Invalid index, " + args.getString(0) + " is not a valid integer."); - return; - } - if (index < 1) { player.printError("Invalid index, must be equal or higher then 1."); return; @@ -194,14 +183,13 @@ public class SnapshotCommands { } @Command( - aliases = { "before" }, - usage = "", - desc = "Choose the nearest snapshot before a date", - min = 1, - max = -1 + name = "before", + desc = "Choose the nearest snapshot before a date" ) @CommandPermissions("worldedit.snapshots.restore") - public void before(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void before(Player player, LocalSession session, + @Arg(desc = "The soonest date that may be used") + ZonedDateTime date) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); @@ -210,37 +198,29 @@ public class SnapshotCommands { return; } - Calendar date = session.detectDate(args.getJoinedStrings(0)); + try { + Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName()); - if (date == null) { - player.printError("Could not detect the date inputted."); - } else { - try { - Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName()); - - if (snapshot == null) { - dateFormat.setTimeZone(session.getTimeZone()); - player.printError("Couldn't find a snapshot before " - + dateFormat.format(date.getTime()) + "."); - } else { - session.setSnapshot(snapshot); - player.print("Snapshot set to: " + snapshot.getName()); - } - } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); + if (snapshot == null) { + player.printError("Couldn't find a snapshot before " + + dateFormat.withZone(session.getTimeZone()).format(date) + "."); + } else { + session.setSnapshot(snapshot); + player.print("Snapshot set to: " + snapshot.getName()); } + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); } } @Command( - aliases = { "after" }, - usage = "", - desc = "Choose the nearest snapshot after a date", - min = 1, - max = -1 + name = "after", + desc = "Choose the nearest snapshot after a date" ) @CommandPermissions("worldedit.snapshots.restore") - public void after(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void after(Player player, LocalSession session, + @Arg(desc = "The soonest date that may be used") + ZonedDateTime date) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); @@ -249,24 +229,17 @@ public class SnapshotCommands { return; } - Calendar date = session.detectDate(args.getJoinedStrings(0)); - - if (date == null) { - player.printError("Could not detect the date inputted."); - } else { - try { - Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName()); - if (snapshot == null) { - dateFormat.setTimeZone(session.getTimeZone()); - player.printError("Couldn't find a snapshot after " - + dateFormat.format(date.getTime()) + "."); - } else { - session.setSnapshot(snapshot); - player.print("Snapshot set to: " + snapshot.getName()); - } - } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); + try { + Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName()); + if (snapshot == null) { + player.printError("Couldn't find a snapshot after " + + dateFormat.withZone(session.getTimeZone()).format(date) + "."); + } else { + session.setSnapshot(snapshot); + player.print("Snapshot set to: " + snapshot.getName()); } + } catch (MissingWorldException ex) { + player.printError("No snapshots were found for this world."); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java index b8d6c7f3f..14a90e2fe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java @@ -19,14 +19,13 @@ package com.sk89q.worldedit.command; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.regions.Region; @@ -36,12 +35,16 @@ import com.sk89q.worldedit.world.snapshot.Snapshot; import com.sk89q.worldedit.world.snapshot.SnapshotRestore; import com.sk89q.worldedit.world.storage.ChunkStore; import com.sk89q.worldedit.world.storage.MissingWorldException; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; import java.io.File; import java.io.IOException; import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class SnapshotUtilCommands { private final WorldEdit we; @@ -51,15 +54,15 @@ public class SnapshotUtilCommands { } @Command( - aliases = { "restore", "/restore" }, - usage = "[snapshot]", - desc = "Restore the selection from a snapshot", - min = 0, - max = 1 + name = "restore", + aliases = { "/restore" }, + desc = "Restore the selection from a snapshot" ) @Logging(REGION) @CommandPermissions("worldedit.snapshots.restore") - public void restore(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { + public void restore(Player player, LocalSession session, EditSession editSession, + @Arg(name = "snapshot", desc = "The snapshot to restore", def = "") + String snapshotName) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); @@ -71,9 +74,9 @@ public class SnapshotUtilCommands { Region region = session.getSelection(player.getWorld()); Snapshot snapshot; - if (args.argsLength() > 0) { + if (snapshotName != null) { try { - snapshot = config.snapshotRepo.getSnapshot(args.getString(0)); + snapshot = config.snapshotRepo.getSnapshot(snapshotName); } catch (InvalidSnapshotException e) { player.printError("That snapshot does not exist or is not available."); return; @@ -110,7 +113,7 @@ public class SnapshotUtilCommands { } } - ChunkStore chunkStore = null; + ChunkStore chunkStore; // Load chunk store try { 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 787859323..5378d5819 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 @@ -40,16 +40,17 @@ import com.sk89q.worldedit.util.report.SystemInfoReport; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.TimeZone; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.TextStyle; +import java.util.Locale; public class WorldEditCommands { - private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); - + private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z"); + private final WorldEdit we; - + public WorldEditCommands(WorldEdit we) { this.we = we; } @@ -138,11 +139,13 @@ public class WorldEditCommands { max = 1 ) public void tz(Player player, LocalSession session, CommandContext args) throws WorldEditException { - TimeZone tz = TimeZone.getTimeZone(args.getString(0)); + ZoneId tz = ZoneId.of(args.getString(0)); session.setTimezone(tz); - player.print("Timezone set for this session to: " + tz.getDisplayName()); + player.print("Timezone set for this session to: " + tz.getDisplayName( + TextStyle.FULL, Locale.ENGLISH + )); player.print("The current time in that timezone is: " - + dateFormat.format(Calendar.getInstance(tz).getTime())); + + dateFormat.format(ZonedDateTime.now(tz))); } @Command( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java new file mode 100644 index 000000000..5d96c28ab --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java @@ -0,0 +1,40 @@ +package com.sk89q.worldedit.command.argument; + +import com.sk89q.worldedit.LocalSession; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Calendar; + +public class ZonedDateTimeConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(ZonedDateTime.class), new ZonedDateTimeConverter()); + } + + private ZonedDateTimeConverter() { + } + + @Override + public String describeAcceptableArguments() { + return "any date"; + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + LocalSession session = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("Need a local session")); + Calendar date = session.detectDate(argument); + if (date == null) { + return FailedConversion.from(new IllegalArgumentException("Not a date: " + argument)); + } + return SuccessfulConversion.fromSingle(date.toInstant().atZone(ZoneOffset.UTC)); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 037617ab3..795d8cddb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -50,6 +50,10 @@ import com.sk89q.worldedit.command.ScriptingCommands; import com.sk89q.worldedit.command.ScriptingCommandsRegistration; import com.sk89q.worldedit.command.SelectionCommands; import com.sk89q.worldedit.command.SelectionCommandsRegistration; +import com.sk89q.worldedit.command.SnapshotCommands; +import com.sk89q.worldedit.command.SnapshotCommandsRegistration; +import com.sk89q.worldedit.command.SnapshotUtilCommands; +import com.sk89q.worldedit.command.SnapshotUtilCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; import com.sk89q.worldedit.command.argument.DirectionConverter; @@ -58,6 +62,7 @@ import com.sk89q.worldedit.command.argument.ExpandAmountConverter; import com.sk89q.worldedit.command.argument.MaskConverter; import com.sk89q.worldedit.command.argument.PatternConverter; import com.sk89q.worldedit.command.argument.VectorConverter; +import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Entity; @@ -201,6 +206,7 @@ public final class PlatformCommandMananger { VectorConverter.register(commandManager); EnumConverter.register(commandManager); ExpandAmountConverter.register(commandManager); + ZonedDateTimeConverter.register(commandManager); } private void registerAlwaysInjectedValues() { @@ -250,6 +256,24 @@ public final class PlatformCommandMananger { .required() .build()); }); + commandManager.register("snapshot", cmd -> { + cmd.aliases(ImmutableList.of("snapshot", "snap")); + cmd.description("Snapshot commands for saving/loading snapshots"); + cmd.action(Command.Action.NULL_ACTION); + + CommandManager manager = DefaultCommandManagerService.getInstance() + .newCommandManager(); + register( + manager, + SnapshotCommandsRegistration.builder(), + new SnapshotCommands(worldEdit) + ); + + cmd.addPart(SubCommandPart.builder("action", "Sub-command to run.") + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() + .build()); + }); commandManager.register("brush", cmd -> { cmd.aliases(ImmutableList.of("br")); cmd.description("Brushing commands"); @@ -318,6 +342,11 @@ public final class PlatformCommandMananger { SelectionCommandsRegistration.builder(), new SelectionCommands(worldEdit) ); + register( + commandManager, + SnapshotUtilCommandsRegistration.builder(), + new SnapshotUtilCommands(worldEdit) + ); // Unported commands are below. Delete once they're added to the main manager above. /* @@ -333,10 +362,6 @@ public final class PlatformCommandMananger { .describeAs("WorldEdit commands") .registerMethods(new WorldEditCommands(worldEdit)) .parent() - .group("snapshot", "snap") - .describeAs("Schematic commands for saving/loading areas") - .registerMethods(new SnapshotCommands(worldEdit)) - .parent() .group("brush", "br") .describeAs("Brushing commands") .register(adapt(new ShapedBrushCommand(new DeformCommand(), "worldedit.brush.deform")), "deform") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java index 0af2b6e18..e05ba9e60 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java @@ -34,7 +34,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; -import java.util.Calendar; +import java.time.ZonedDateTime; import java.util.zip.ZipFile; /** @@ -46,7 +46,7 @@ public class Snapshot implements Comparable { protected File file; protected String name; - protected Calendar date; + protected ZonedDateTime date; /** * Construct a snapshot restoration operation. @@ -185,7 +185,7 @@ public class Snapshot implements Comparable { * * @return date for the snapshot */ - public Calendar getDate() { + public ZonedDateTime getDate() { return date; } @@ -194,7 +194,7 @@ public class Snapshot implements Comparable { * * @param date the date of the snapshot */ - public void setDate(Calendar date) { + public void setDate(ZonedDateTime date) { this.date = date; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java index 72650a408..1838c2747 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java @@ -23,15 +23,16 @@ package com.sk89q.worldedit.world.snapshot; import com.sk89q.worldedit.world.storage.MissingWorldException; +import javax.annotation.Nullable; import java.io.File; import java.io.FilenameFilter; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; -import javax.annotation.Nullable; - /** * A repository contains zero or more snapshots. */ @@ -115,12 +116,12 @@ public class SnapshotRepository { * @return a snapshot or null */ @Nullable - public Snapshot getSnapshotAfter(Calendar date, String world) throws MissingWorldException { + public Snapshot getSnapshotAfter(ZonedDateTime date, String world) throws MissingWorldException { List snapshots = getSnapshots(true, world); Snapshot last = null; for (Snapshot snapshot : snapshots) { - if (snapshot.getDate() != null && snapshot.getDate().before(date)) { + if (snapshot.getDate() != null && snapshot.getDate().compareTo(date) < 0) { return last; } @@ -137,12 +138,12 @@ public class SnapshotRepository { * @return a snapshot or null */ @Nullable - public Snapshot getSnapshotBefore(Calendar date, String world) throws MissingWorldException { + public Snapshot getSnapshotBefore(ZonedDateTime date, String world) throws MissingWorldException { List snapshots = getSnapshots(false, world); Snapshot last = null; for (Snapshot snapshot : snapshots) { - if (snapshot.getDate().after(date)) { + if (snapshot.getDate().compareTo(date) > 0) { return last; } @@ -161,7 +162,7 @@ public class SnapshotRepository { for (SnapshotDateParser parser : dateParsers) { Calendar date = parser.detectDate(snapshot.getFile()); if (date != null) { - snapshot.setDate(date); + snapshot.setDate(date.toInstant().atZone(ZoneOffset.UTC)); return; } } From e447ac55dbd369b5bfb4412f5199aad660a8cac7 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 24 Apr 2019 00:00:56 -0700 Subject: [PATCH 046/366] Port super pickaxe commands --- .../command/SuperPickaxeCommands.java | 42 +++++++++---------- .../argument/ZonedDateTimeConverter.java | 19 +++++++++ .../platform/PlatformCommandMananger.java | 27 +++++++++--- 3 files changed, 59 insertions(+), 29 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java index a3e21db8a..754473a9a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SuperPickaxeCommands.java @@ -19,9 +19,6 @@ package com.sk89q.worldedit.command; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -29,8 +26,14 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.tool.AreaPickaxe; import com.sk89q.worldedit.command.tool.RecursivePickaxe; import com.sk89q.worldedit.command.tool.SinglePickaxe; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class SuperPickaxeCommands { private final WorldEdit we; @@ -39,32 +42,26 @@ public class SuperPickaxeCommands { } @Command( - aliases = { "single" }, - usage = "", - desc = "Enable the single block super pickaxe mode", - min = 0, - max = 0 + name = "single", + desc = "Enable the single block super pickaxe mode" ) @CommandPermissions("worldedit.superpickaxe") public void single(Player player, LocalSession session) throws WorldEditException { - session.setSuperPickaxe(new SinglePickaxe()); session.enableSuperPickAxe(); player.print("Mode changed. Left click with a pickaxe. // to disable."); } @Command( - aliases = { "area" }, - usage = "", - desc = "Enable the area super pickaxe pickaxe mode", - min = 1, - max = 1 + name = "area", + desc = "Enable the area super pickaxe pickaxe mode" ) @CommandPermissions("worldedit.superpickaxe.area") - public void area(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void area(Player player, LocalSession session, + @Arg(desc = "The range of the area pickaxe") + int range) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); - int range = args.getInteger(0); if (range > config.maxSuperPickaxeSize) { player.printError("Maximum range: " + config.maxSuperPickaxeSize); @@ -77,17 +74,16 @@ public class SuperPickaxeCommands { } @Command( - aliases = { "recur", "recursive" }, - usage = "", - desc = "Enable the recursive super pickaxe pickaxe mode", - min = 1, - max = 1 + name = "recursive", + aliases = { "recur" }, + desc = "Enable the recursive super pickaxe pickaxe mode" ) @CommandPermissions("worldedit.superpickaxe.recursive") - public void recursive(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void recursive(Player player, LocalSession session, + @Arg(desc = "The range of the recursive pickaxe") + double range) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); - double range = args.getDouble(0); if (range > config.maxSuperPickaxeSize) { player.printError("Maximum range: " + config.maxSuperPickaxeSize); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java index 5d96c28ab..4efd97555 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ZonedDateTimeConverter.java @@ -1,3 +1,22 @@ +/* + * 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.command.argument; import com.sk89q.worldedit.LocalSession; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 795d8cddb..b6c2b6c89 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -54,6 +54,8 @@ import com.sk89q.worldedit.command.SnapshotCommands; import com.sk89q.worldedit.command.SnapshotCommandsRegistration; import com.sk89q.worldedit.command.SnapshotUtilCommands; import com.sk89q.worldedit.command.SnapshotUtilCommandsRegistration; +import com.sk89q.worldedit.command.SuperPickaxeCommands; +import com.sk89q.worldedit.command.SuperPickaxeCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; import com.sk89q.worldedit.command.argument.DirectionConverter; @@ -257,7 +259,7 @@ public final class PlatformCommandMananger { .build()); }); commandManager.register("snapshot", cmd -> { - cmd.aliases(ImmutableList.of("snapshot", "snap")); + cmd.aliases(ImmutableList.of("snap")); cmd.description("Snapshot commands for saving/loading snapshots"); cmd.action(Command.Action.NULL_ACTION); @@ -274,6 +276,24 @@ public final class PlatformCommandMananger { .required() .build()); }); + commandManager.register("superpickaxe", cmd -> { + cmd.aliases(ImmutableList.of("pickaxe", "sp")); + cmd.description("Super-pickaxe commands"); + cmd.action(Command.Action.NULL_ACTION); + + CommandManager manager = DefaultCommandManagerService.getInstance() + .newCommandManager(); + register( + manager, + SuperPickaxeCommandsRegistration.builder(), + new SuperPickaxeCommands(worldEdit) + ); + + cmd.addPart(SubCommandPart.builder("action", "Sub-command to run.") + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() + .build()); + }); commandManager.register("brush", cmd -> { cmd.aliases(ImmutableList.of("br")); cmd.description("Brushing commands"); @@ -353,7 +373,6 @@ public final class PlatformCommandMananger { dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new SnapshotUtilCommands(worldEdit)) .registerMethods(new ToolUtilCommands(worldEdit)) .registerMethods(new ToolCommands(worldEdit)) .registerMethods(new UtilityCommands(worldEdit)) @@ -372,10 +391,6 @@ public final class PlatformCommandMananger { .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y-=1", Mode.RAW_COORD), "Raise one block"), "worldedit.brush.raise")), "raise") .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y+=1", Mode.RAW_COORD), "Lower one block"), "worldedit.brush.lower")), "lower") .parent() - .group("superpickaxe", "pickaxe", "sp") - .describeAs("Super-pickaxe commands") - .registerMethods(new SuperPickaxeCommands(worldEdit)) - .parent() .group("tool") .describeAs("Bind functions to held items") .registerMethods(new ToolCommands(worldEdit)) From 5606e752c2ead3f3904d1c45afb48f6388409f78 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Thu, 25 Apr 2019 19:11:58 +1000 Subject: [PATCH 047/366] Use wrappers for the Format-type components --- config/checkstyle/import-control.xml | 1 - .../worldedit/command/SelectionCommands.java | 4 ++-- .../worldedit/command/UtilityCommands.java | 19 ++++++++------- .../component/{Code.java => CodeFormat.java} | 24 ++++++++++++++----- .../formatting/component/CommandListBox.java | 5 ++-- .../formatting/component/CommandUsageBox.java | 13 +++++----- .../{Error.java => ErrorFormat.java} | 21 +++++++++++++--- .../{Label.java => LabelFormat.java} | 21 +++++++++++++--- .../util/formatting/component/MessageBox.java | 4 ++-- .../{Subtle.java => SubtleFormat.java} | 21 +++++++++++++--- .../component/TextComponentProducer.java | 23 +++++++++++++++++- 11 files changed, 117 insertions(+), 39 deletions(-) rename worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/{Code.java => CodeFormat.java} (66%) rename worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/{Error.java => ErrorFormat.java} (65%) rename worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/{Label.java => LabelFormat.java} (65%) rename worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/{Subtle.java => SubtleFormat.java} (65%) diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index b4a2f4808..28ccad1e4 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -16,7 +16,6 @@ - diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index cd15be1ff..3c1be05fd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -56,7 +56,7 @@ import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.component.CommandListBox; -import com.sk89q.worldedit.util.formatting.component.Subtle; +import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; @@ -755,7 +755,7 @@ public class SelectionCommands { } else { CommandListBox box = new CommandListBox("Selection modes"); TextComponentProducer contents = box.getContents(); - contents.append(new Subtle("Select one of the modes below:").append(Component.newline()).create()); + contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline(); box.appendCommand("cuboid", "Select two corners of a cuboid", "//sel cuboid"); box.appendCommand("extend", "Fast cuboid selection mode", "//sel extend"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index bd0c8ba53..2e2defc19 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -58,14 +58,15 @@ import com.sk89q.worldedit.util.command.CommandMapping; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.PrimaryAliasComparator; import com.sk89q.worldedit.util.command.binding.Text; -import com.sk89q.worldedit.util.formatting.component.Code; +import com.sk89q.worldedit.util.formatting.component.CodeFormat; import com.sk89q.worldedit.util.formatting.component.CommandListBox; import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; -import com.sk89q.worldedit.util.formatting.component.Error; -import com.sk89q.worldedit.util.formatting.component.Subtle; +import com.sk89q.worldedit.util.formatting.component.ErrorFormat; +import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; @@ -671,17 +672,19 @@ public class UtilityCommands { // Box CommandListBox box = new CommandListBox(String.format("Help: page %d/%d ", page + 1, pageTotal)); - TextComponentProducer tip = new Subtle(""); + TextComponentProducer tip = new TextComponentProducer(); + tip.getBuilder().content("").color(TextColor.GRAY); TextComponentProducer contents = box.getContents(); if (offset >= aliases.size()) { - tip.append(new Error(String.format("There is no page %d (total number of pages is %d).", page + 1, pageTotal)).create()).append(Component.newline()); + tip.append(ErrorFormat.wrap(String.format("There is no page %d (total number of pages is %d).", page + 1, pageTotal))).newline(); } else { List list = aliases.subList(offset, Math.min(offset + perPage, aliases.size())); - tip.append(TextComponent.of("Type ")); - tip.append(new Code("//help ").append(TextComponent.of(" []")).create()); - tip.append(TextComponent.of(" for more information.")).append(Component.newline()); + tip.append("Type "); + tip.append(CodeFormat.wrap("//help ")); + tip.append(" [] for more information."); + tip.newline(); // Add each command for (CommandMapping mapping : list) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java similarity index 66% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java index 6cbad7f3a..134239546 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Code.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java @@ -19,18 +19,30 @@ package com.sk89q.worldedit.util.formatting.component; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a fragment representing a command that is to be typed. */ -public class Code extends TextComponentProducer { +public class CodeFormat extends TextComponentProducer { - /** - * Create a new instance. - */ - public Code(String message) { - getBuilder().content(message).color(TextColor.AQUA); + private CodeFormat() { + getBuilder().content("").color(TextColor.AQUA); } + /** + * Creates a CodeFormat with the given message. + * + * @param texts The text + * @return The Component + */ + public static Component wrap(String ... texts) { + CodeFormat code = new CodeFormat(); + for (String text: texts) { + code.append(text); + } + + return code.create(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java index 846d08853..ac360e99c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; @@ -44,7 +43,7 @@ public class CommandListBox extends MessageBox { public CommandListBox appendCommand(String alias, String description, String insertion) { if (!first) { - getContents().append(Component.newline()); + getContents().newline(); } TextComponent commandName = TextComponent.of(alias, TextColor.GOLD); if (insertion != null) { @@ -53,7 +52,7 @@ public class CommandListBox extends MessageBox { .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select"))); } getContents().append(commandName.append(TextComponent.of(": "))); - getContents().append(TextComponent.of(description)); + getContents().append(description); first = false; return this; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index e15d862cc..04a31df3b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -29,7 +29,6 @@ import com.sk89q.worldedit.util.command.Description; import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.PrimaryAliasComparator; import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import java.util.ArrayList; import java.util.List; @@ -88,20 +87,20 @@ public class CommandUsageBox extends TextComponentProducer { TextComponentProducer contents = new TextComponentProducer(); if (description.getUsage() != null) { - contents.append(new Label("Usage: ").create()); - contents.append(TextComponent.of(description.getUsage())); + contents.append(LabelFormat.wrap("Usage: ")); + contents.append(description.getUsage()); } else { - contents.append(new Subtle("Usage information is not available.").create()); + contents.append(SubtleFormat.wrap("Usage information is not available.")); } contents.append(Component.newline()); if (description.getHelp() != null) { - contents.append(TextComponent.of(description.getHelp())); + contents.append(description.getHelp()); } else if (description.getDescription() != null) { - contents.append(TextComponent.of(description.getDescription())); + contents.append(description.getDescription()); } else { - contents.append(new Subtle("No further help is available.").create()); + contents.append(SubtleFormat.wrap("No further help is available.")); } MessageBox box = new MessageBox("Help for " + commandString, contents); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java similarity index 65% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java index 50cef22f2..b30ad8324 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Error.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java @@ -19,18 +19,33 @@ package com.sk89q.worldedit.util.formatting.component; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a fragment representing an error. */ -public class Error extends TextComponentProducer { +public class ErrorFormat extends TextComponentProducer { /** * Create a new instance. */ - public Error(String message) { - getBuilder().content(message).color(TextColor.RED); + private ErrorFormat() { + getBuilder().content("").color(TextColor.RED); } + /** + * Creates an ErrorFormat with the given message. + * + * @param texts The text + * @return The Component + */ + public static Component wrap(String ... texts) { + ErrorFormat error = new ErrorFormat(); + for (String component : texts) { + error.append(component); + } + + return error.create(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java similarity index 65% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java index 02d438f8d..4dda69349 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Label.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java @@ -19,18 +19,33 @@ package com.sk89q.worldedit.util.formatting.component; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a fragment representing a label. */ -public class Label extends TextComponentProducer { +public class LabelFormat extends TextComponentProducer { /** * Create a new instance. */ - public Label(String message) { - getBuilder().content(message).color(TextColor.YELLOW); + private LabelFormat() { + getBuilder().content("").color(TextColor.YELLOW); } + /** + * Creates a LabelFormat with the given message. + * + * @param texts The text + * @return The Component + */ + public static Component wrap(String ... texts) { + LabelFormat label = new LabelFormat(); + for (String component : texts) { + label.append(component); + } + + return label.create(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java index 5193f0e6b..6828589bc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java @@ -47,12 +47,12 @@ public class MessageBox extends TextComponentProducer { append(TextComponent.of(createBorder(leftSide), TextColor.YELLOW)); } append(Component.space()); - append(TextComponent.of(title)); + append(title); append(Component.space()); if (rightSide > 0) { append(TextComponent.of(createBorder(rightSide), TextColor.YELLOW)); } - append(Component.newline()); + newline(); this.contents = contents; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java similarity index 65% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java index 609824838..5987675f7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/Subtle.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java @@ -19,18 +19,33 @@ package com.sk89q.worldedit.util.formatting.component; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** * Represents a subtle part of the message. */ -public class Subtle extends TextComponentProducer { +public class SubtleFormat extends TextComponentProducer { /** * Create a new instance. */ - public Subtle(String message) { - getBuilder().color(TextColor.GRAY).content(message); + private SubtleFormat() { + getBuilder().content("").color(TextColor.GRAY); } + /** + * Creates a SubtleFormat with the given message. + * + * @param texts The text + * @return The Component + */ + public static Component wrap(String ... texts) { + SubtleFormat subtle = new SubtleFormat(); + for (String component : texts) { + subtle.append(component); + } + + return subtle.create(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java index 2c3228ee2..32a9f8d30 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java @@ -31,7 +31,7 @@ public class TextComponentProducer { } /** - * Adds a component as a child to this Producer + * Adds a component as a child to this Producer. * * @param component The component * @return The producer, for chaining @@ -41,6 +41,27 @@ public class TextComponentProducer { return this; } + /** + * Adds a string as a child to this Producer. + * + * @param string The text + * @return The producer, for chaining + */ + public TextComponentProducer append(String string) { + getBuilder().append(TextComponent.of(string)); + return this; + } + + /** + * Adds a newline as a child to this Producer. + * + * @return The producer, for chaining + */ + public TextComponentProducer newline() { + getBuilder().append(Component.newline()); + return this; + } + public TextComponent create() { return builder.build(); } From b1e43b7561906c9cbab24b04095b314412353bbe Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Thu, 25 Apr 2019 19:20:29 +1000 Subject: [PATCH 048/366] wrap to TextComponent --- .../sk89q/worldedit/util/formatting/component/CodeFormat.java | 4 ++-- .../worldedit/util/formatting/component/ErrorFormat.java | 4 ++-- .../worldedit/util/formatting/component/LabelFormat.java | 4 ++-- .../worldedit/util/formatting/component/SubtleFormat.java | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java index 134239546..a92590bac 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CodeFormat.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** @@ -37,7 +37,7 @@ public class CodeFormat extends TextComponentProducer { * @param texts The text * @return The Component */ - public static Component wrap(String ... texts) { + public static TextComponent wrap(String ... texts) { CodeFormat code = new CodeFormat(); for (String text: texts) { code.append(text); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java index b30ad8324..35343ca56 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/ErrorFormat.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** @@ -40,7 +40,7 @@ public class ErrorFormat extends TextComponentProducer { * @param texts The text * @return The Component */ - public static Component wrap(String ... texts) { + public static TextComponent wrap(String ... texts) { ErrorFormat error = new ErrorFormat(); for (String component : texts) { error.append(component); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java index 4dda69349..f0a487114 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/LabelFormat.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** @@ -40,7 +40,7 @@ public class LabelFormat extends TextComponentProducer { * @param texts The text * @return The Component */ - public static Component wrap(String ... texts) { + public static TextComponent wrap(String ... texts) { LabelFormat label = new LabelFormat(); for (String component : texts) { label.append(component); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java index 5987675f7..310cc4e01 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SubtleFormat.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.util.formatting.component; -import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; /** @@ -40,7 +40,7 @@ public class SubtleFormat extends TextComponentProducer { * @param texts The text * @return The Component */ - public static Component wrap(String ... texts) { + public static TextComponent wrap(String ... texts) { SubtleFormat subtle = new SubtleFormat(); for (String component : texts) { subtle.append(component); From 4f5f9c8a5df016734b4500c28864984a47eb6104 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Thu, 25 Apr 2019 19:38:32 +1000 Subject: [PATCH 049/366] Add forge support to the text system. --- .../java/com/sk89q/worldedit/forge/ForgePlayer.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index 5dc11aaf6..edc5275ab 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -31,10 +31,11 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; - -import com.sk89q.worldedit.util.formatting.text.TextComponent; +import io.netty.buffer.Unpooled; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; @@ -43,6 +44,7 @@ import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextFormatting; @@ -50,8 +52,6 @@ import java.util.UUID; import javax.annotation.Nullable; -import io.netty.buffer.Unpooled; - public class ForgePlayer extends AbstractPlayerActor { private final EntityPlayerMP player; @@ -144,7 +144,7 @@ public class ForgePlayer extends AbstractPlayerActor { @Override public void print(TextComponent component) { - // TODO + this.player.sendMessage(ITextComponent.Serializer.fromJson(GsonComponentSerializer.INSTANCE.serialize(component))); } private void sendColorized(String msg, TextFormatting formatting) { From f70557e3dac50d7796c0d24869275c84278378d4 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Thu, 25 Apr 2019 22:48:15 +1000 Subject: [PATCH 050/366] Provide a warning when an invalid property is entered rather than failing. Fixes WorldEdit entirely failing on new MC versions. --- .../bukkit/adapter/BukkitImplLoader.java | 2 +- .../factory/parser/DefaultBlockParser.java | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java index a03a9f229..612290995 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java @@ -52,7 +52,7 @@ public class BukkitImplLoader { "**\n" + "** When working with blocks or undoing, chests will be empty, signs\n" + "** will be blank, and so on. There will be no support for entity\n" + - "** and biome-related functions.\n" + + "** and block property-related functions.\n" + "**\n" + "** Please see http://wiki.sk89q.com/wiki/WorldEdit/Bukkit_adapters\n" + "**********************************************\n"; 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 4f3793adb..72bf195da 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 @@ -19,6 +19,7 @@ package com.sk89q.worldedit.extension.factory.parser; +import com.google.common.collect.Maps; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.NotABlockException; import com.sk89q.worldedit.WorldEdit; @@ -38,6 +39,7 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.formatting.component.ErrorFormat; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -148,7 +150,7 @@ public class DefaultBlockParser extends InputParser { } } - private static Map, Object> parseProperties(BlockType type, String[] stateProperties) throws NoMatchException { + private static Map, Object> parseProperties(BlockType type, String[] stateProperties, ParserContext context) throws NoMatchException { Map, Object> blockStates = new HashMap<>(); if (stateProperties.length > 0) { // Block data not yet detected @@ -163,7 +165,14 @@ public class DefaultBlockParser extends InputParser { @SuppressWarnings("unchecked") Property propertyKey = (Property) type.getPropertyMap().get(parts[0]); if (propertyKey == null) { - throw new NoMatchException("Unknown property " + parts[0] + " for block " + type.getName()); + if (context.getActor() != null) { + context.getActor().print(ErrorFormat.wrap("Unknown property ", parts[0], " for block ", type.getName(), + ". Defaulting to base.")); + } else { + WorldEdit.logger.warn("Unknown property " + parts[0] + " for block " + type.getName()); +// throw new NoMatchException("Unknown property " + parts[0] + " for block " + type.getName()); + } + return Maps.newHashMap(); } if (blockStates.containsKey(propertyKey)) { throw new NoMatchException("Duplicate property " + parts[0]); @@ -222,7 +231,7 @@ public class DefaultBlockParser extends InputParser { typeString = blockAndExtraData[0].substring(0, stateStart); stateString = blockAndExtraData[0].substring(stateStart + 1, blockAndExtraData[0].length() - 1); } - if (typeString == null || typeString.isEmpty()) { + if (typeString.isEmpty()) { throw new InputParseException("Invalid format"); } String[] stateProperties = EMPTY_STRING_ARRAY; @@ -270,7 +279,7 @@ public class DefaultBlockParser extends InputParser { } } - blockStates.putAll(parseProperties(blockType, stateProperties)); + blockStates.putAll(parseProperties(blockType, stateProperties, context)); if (!context.isPreferringWildcard()) { // No wildcards allowed => eliminate them. (Start with default state) From c325b789b2588e9ce303cc5e10ca5752156d5135 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Thu, 25 Apr 2019 23:15:09 +1000 Subject: [PATCH 051/366] Revert lighting changes and add a 1.14 adapter --- .../bukkit/adapter/impl/Spigot_v1_13_R1.class | Bin 25386 -> 25466 bytes .../bukkit/adapter/impl/Spigot_v1_13_R2.class | Bin 25408 -> 25488 bytes .../adapter/impl/Spigot_v1_13_R2_2$1.class | Bin 965 -> 965 bytes .../adapter/impl/Spigot_v1_13_R2_2.class | Bin 25474 -> 25554 bytes .../adapter/impl/Spigot_v1_14_R1$1.class | Bin 0 -> 959 bytes .../bukkit/adapter/impl/Spigot_v1_14_R1.class | Bin 0 -> 25746 bytes .../com/sk89q/worldedit/forge/ForgeWorld.java | 2 +- 7 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1$1.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1.class diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class index 3890dc4793417efa709a1ca275a10fa7aa4524cc..31b547024c5440aee3a7372b5abbb9891a6239e6 100644 GIT binary patch delta 7848 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 IRnw~f0m$bfJ^%m! delta 8666 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1$1.class new file mode 100644 index 0000000000000000000000000000000000000000..185607a49fd488a9be2d8a8856622980e432d8de GIT binary patch literal 959 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 Ht0DgnnvVvQ literal 0 HcmV?d00001 diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 152b1ac7d..3aadc12cc 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -178,7 +178,7 @@ public class ForgeWorld extends AbstractWorld { } if (successful && notifyAndLight) { - //world.checkLight(pos); + world.checkLight(pos); world.markAndNotifyBlock(pos, chunk, old, newState, UPDATE | NOTIFY); } From 8c2b725f42abe1d54c89bf1b88b4e13f58c3b03c Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 25 Apr 2019 12:49:03 -0700 Subject: [PATCH 052/366] Port toll / tool util commands, add more enums --- .../java/com/sk89q/worldedit/EditSession.java | 9 -- .../worldedit/command/GeneralCommands.java | 55 ++++----- .../sk89q/worldedit/command/ToolCommands.java | 104 +++++++----------- .../worldedit/command/ToolUtilCommands.java | 98 ++++++++--------- .../command/argument/BooleanConverter.java | 65 +++++++++++ .../command/argument/EnumConverter.java | 51 ++++++++- .../platform/PlatformCommandMananger.java | 18 ++- .../sk89q/worldedit/util/TreeGenerator.java | 9 +- 8 files changed, 238 insertions(+), 171 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java 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 bf26a0a1f..a831c10b8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -175,15 +175,6 @@ public class EditSession implements Extent, AutoCloseable { public String getDisplayName() { return this.displayName; } - - public static Optional getFromDisplayName(String name) { - for (ReorderMode mode : values()) { - if (mode.getDisplayName().equalsIgnoreCase(name)) { - return Optional.of(mode); - } - } - return Optional.empty(); - } } @SuppressWarnings("ProtectedField") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index a5a0a9796..220b30de2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -122,23 +122,18 @@ public class GeneralCommands { ) @CommandPermissions("worldedit.fast") public void fast(Player player, LocalSession session, - @Arg(name = "on|off", desc = "The new fast mode state", def = "toggle") - String newState) throws WorldEditException { - - if (session.hasFastMode()) { - if ("on".equals(newState)) { - player.printError("Fast mode already enabled."); - return; - } + @Arg(desc = "The new fast mode state", def = "") + Boolean fastMode) throws WorldEditException { + boolean hasFastMode = session.hasFastMode(); + if (fastMode != null && fastMode == hasFastMode) { + player.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + "."); + return; + } + if (hasFastMode) { session.setFastMode(false); player.print("Fast mode disabled."); } else { - if ("off".equals(newState)) { - player.printError("Fast mode already disabled."); - return; - } - session.setFastMode(true); player.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes."); } @@ -150,18 +145,11 @@ public class GeneralCommands { ) @CommandPermissions("worldedit.reorder") public void reorderMode(Player player, LocalSession session, - @Arg(name = "multi|fast|none", desc = "The reorder mode", def = "") - String newState) throws WorldEditException { - if (newState == null) { + @Arg(desc = "The reorder mode", def = "") + EditSession.ReorderMode reorderMode) throws WorldEditException { + if (reorderMode == null) { player.print("The reorder mode is " + session.getReorderMode().getDisplayName()); } else { - java.util.Optional reorderModeOptional = EditSession.ReorderMode.getFromDisplayName(newState); - if (!reorderModeOptional.isPresent()) { - player.printError("Unknown reorder mode!"); - return; - } - - EditSession.ReorderMode reorderMode = reorderModeOptional.get(); session.setReorderMode(reorderMode); player.print("The reorder mode is now " + session.getReorderMode().getDisplayName()); } @@ -173,26 +161,21 @@ public class GeneralCommands { ) @CommandPermissions("worldedit.drawsel") public void drawSelection(Player player, LocalSession session, - @Arg(name = "on|off", desc = "The new fast mode state", def = "toggle") - String newState) throws WorldEditException { + @Arg(desc = "The new draw selection state", def = "toggle") + Boolean drawSelection) throws WorldEditException { if (!WorldEdit.getInstance().getConfiguration().serverSideCUI) { throw new DisallowedUsageException("This functionality is disabled in the configuration!"); } - if (session.shouldUseServerCUI()) { - if ("on".equals(newState)) { - player.printError("Server CUI already enabled."); - return; - } - + boolean useServerCui = session.shouldUseServerCUI(); + if (drawSelection != null && drawSelection == useServerCui) { + player.printError("Server CUI already " + (useServerCui ? "enabled" : "disabled") + "."); + return; + } + if (useServerCui) { session.setUseServerCUI(false); session.updateServerCUI(player); player.print("Server CUI disabled."); } else { - if ("off".equals(newState)) { - player.printError("Server CUI already disabled."); - return; - } - session.setUseServerCUI(true); session.updateServerCUI(player); player.print("Server CUI enabled. This only supports cuboid regions, with a maximum size of 32x32x32."); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index c61c2fc92..2af2b8750 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -19,9 +19,6 @@ package com.sk89q.worldedit.command; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -35,12 +32,18 @@ import com.sk89q.worldedit.command.tool.FloodFillTool; import com.sk89q.worldedit.command.tool.LongRangeBuildTool; import com.sk89q.worldedit.command.tool.QueryTool; import com.sk89q.worldedit.command.tool.TreePlanter; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.TreeGenerator; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class ToolCommands { private final WorldEdit we; @@ -49,11 +52,8 @@ public class ToolCommands { } @Command( - aliases = { "none" }, - usage = "", - desc = "Unbind a bound tool from your current item", - min = 0, - max = 0 + name = "none", + desc = "Unbind a bound tool from your current item" ) public void none(Player player, LocalSession session) throws WorldEditException { @@ -62,11 +62,8 @@ public class ToolCommands { } @Command( - aliases = { "info" }, - usage = "", - desc = "Block information tool", - min = 0, - max = 0 + name = "info", + desc = "Block information tool" ) @CommandPermissions("worldedit.tool.info") public void info(Player player, LocalSession session) throws WorldEditException { @@ -78,49 +75,34 @@ public class ToolCommands { } @Command( - aliases = { "tree" }, - usage = "[type]", - desc = "Tree generator tool", - min = 0, - max = 1 + name = "tree", + desc = "Tree generator tool" ) @CommandPermissions("worldedit.tool.tree") - public void tree(Player player, LocalSession session, CommandContext args) throws WorldEditException { - - TreeGenerator.TreeType type = args.argsLength() > 0 - ? TreeGenerator.lookup(args.getString(0)) - : TreeGenerator.TreeType.TREE; - - if (type == null) { - player.printError("Tree type '" + args.getString(0) + "' is unknown."); - return; - } - + public void tree(Player player, LocalSession session, + @Arg(desc = "Type of tree to generate", def = "tree") + TreeGenerator.TreeType type) throws WorldEditException { BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); session.setTool(itemStack.getType(), new TreePlanter(type)); player.print("Tree tool bound to " + itemStack.getType().getName() + "."); } @Command( - aliases = { "repl" }, - usage = "", - desc = "Block replacer tool", - min = 1, - max = 1 + name = "repl", + desc = "Block replacer tool" ) @CommandPermissions("worldedit.tool.replacer") - public void repl(Player player, LocalSession session, Pattern pattern) throws WorldEditException { + public void repl(Player player, LocalSession session, + @Arg(desc = "The pattern of blocks to place") + Pattern pattern) throws WorldEditException { BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); session.setTool(itemStack.getType(), new BlockReplacer(pattern)); player.print("Block replacer tool bound to " + itemStack.getType().getName() + "."); } @Command( - aliases = { "cycler" }, - usage = "", - desc = "Block data cycler tool", - min = 0, - max = 0 + name = "cycler", + desc = "Block data cycler tool" ) @CommandPermissions("worldedit.tool.data-cycler") public void cycler(Player player, LocalSession session) throws WorldEditException { @@ -131,14 +113,16 @@ public class ToolCommands { } @Command( - aliases = { "floodfill", "flood" }, - usage = " ", - desc = "Flood fill tool", - min = 2, - max = 2 + name = "floodfill", + aliases = { "flood" }, + desc = "Flood fill tool" ) @CommandPermissions("worldedit.tool.flood-fill") - public void floodFill(Player player, LocalSession session, Pattern pattern, int range) throws WorldEditException { + public void floodFill(Player player, LocalSession session, + @Arg(desc = "The pattern to flood fill") + Pattern pattern, + @Arg(desc = "The range to perform the fill") + int range) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); @@ -153,11 +137,8 @@ public class ToolCommands { } @Command( - aliases = { "deltree" }, - usage = "", - desc = "Floating tree remover tool", - min = 0, - max = 0 + name = "deltree", + desc = "Floating tree remover tool" ) @CommandPermissions("worldedit.tool.deltree") public void deltree(Player player, LocalSession session) throws WorldEditException { @@ -169,11 +150,8 @@ public class ToolCommands { } @Command( - aliases = { "farwand" }, - usage = "", - desc = "Wand at a distance tool", - min = 0, - max = 0 + name = "farwand", + desc = "Wand at a distance tool" ) @CommandPermissions("worldedit.tool.farwand") public void farwand(Player player, LocalSession session) throws WorldEditException { @@ -184,14 +162,16 @@ public class ToolCommands { } @Command( - aliases = { "lrbuild", "/lrbuild" }, - usage = " ", - desc = "Long-range building tool", - min = 2, - max = 2 + name = "lrbuild", + aliases = { "/lrbuild" }, + desc = "Long-range building tool" ) @CommandPermissions("worldedit.tool.lrbuild") - public void longrangebuildtool(Player player, LocalSession session, Pattern secondary, Pattern primary) throws WorldEditException { + public void longrangebuildtool(Player player, LocalSession session, + @Arg(desc = "Block to set on left-click") + Pattern primary, + @Arg(desc = "Block to set on right-click") + Pattern secondary) throws WorldEditException { BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); session.setTool(itemStack.getType(), new LongRangeBuildTool(primary, secondary)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java index df1637880..6f53cc1bf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java @@ -19,21 +19,23 @@ package com.sk89q.worldedit.command; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.util.HandSide; -import com.sk89q.worldedit.util.command.parametric.Optional; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; /** * Tool commands. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class ToolUtilCommands { private final WorldEdit we; @@ -42,44 +44,37 @@ public class ToolUtilCommands { } @Command( - aliases = { "/", "," }, - usage = "[on|off]", - desc = "Toggle the super pickaxe function", - min = 0, - max = 1 + name = "/", + aliases = { "," }, + desc = "Toggle the super pickaxe function" ) @CommandPermissions("worldedit.superpickaxe") - public void togglePickaxe(Player player, LocalSession session, CommandContext args) throws WorldEditException { - - String newState = args.getString(0, null); - if (session.hasSuperPickAxe()) { - if ("on".equals(newState)) { - player.printError("Super pick axe already enabled."); - return; - } - + public void togglePickaxe(Player player, LocalSession session, + @Arg(desc = "The new super pickaxe state", def = "") + Boolean superPickaxe) throws WorldEditException { + boolean hasSuperPickAxe = session.hasSuperPickAxe(); + if (superPickaxe != null && superPickaxe == hasSuperPickAxe) { + player.printError("Super pickaxe already " + (superPickaxe ? "enabled" : "disabled") + "."); + return; + } + if (hasSuperPickAxe) { session.disableSuperPickAxe(); - player.print("Super pick axe disabled."); + player.print("Super pickaxe disabled."); } else { - if ("off".equals(newState)) { - player.printError("Super pick axe already disabled."); - return; - } session.enableSuperPickAxe(); - player.print("Super pick axe enabled."); + player.print("Super pickaxe enabled."); } } @Command( - aliases = { "mask" }, - usage = "[mask]", - desc = "Set the brush mask", - min = 0, - max = -1 + name = "mask", + desc = "Set the brush mask" ) @CommandPermissions("worldedit.brush.options.mask") - public void mask(Player player, LocalSession session, @Optional Mask mask) throws WorldEditException { + public void mask(Player player, LocalSession session, + @Arg(desc = "The mask to set", def = "") + Mask mask) throws WorldEditException { if (mask == null) { session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setMask(null); player.print("Brush mask disabled."); @@ -90,46 +85,41 @@ public class ToolUtilCommands { } @Command( - aliases = { "mat", "material" }, - usage = "[pattern]", - desc = "Set the brush material", - min = 1, - max = 1 + name = "material", + aliases = { "material" }, + desc = "Set the brush material" ) @CommandPermissions("worldedit.brush.options.material") - public void material(Player player, LocalSession session, Pattern pattern) throws WorldEditException { + public void material(Player player, LocalSession session, + @Arg(desc = "The pattern of blocks to use") + Pattern pattern) throws WorldEditException { session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setFill(pattern); player.print("Brush material set."); } @Command( - aliases = { "range" }, - usage = "[pattern]", - desc = "Set the brush range", - min = 1, - max = 1 - ) + name = "range", + desc = "Set the brush range" + ) @CommandPermissions("worldedit.brush.options.range") - public void range(Player player, LocalSession session, CommandContext args) throws WorldEditException { - int range = args.getInteger(0); + public void range(Player player, LocalSession session, + @Arg(desc = "The range of the brush") + int range) throws WorldEditException { session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setRange(range); player.print("Brush range set."); } @Command( - aliases = { "size" }, - usage = "[pattern]", - desc = "Set the brush size", - min = 1, - max = 1 + name = "size", + desc = "Set the brush size" ) @CommandPermissions("worldedit.brush.options.size") - public void size(Player player, LocalSession session, CommandContext args) throws WorldEditException { + public void size(Player player, LocalSession session, + @Arg(desc = "The size of the brush") + int size) throws WorldEditException { + we.checkMaxBrushRadius(size); - int radius = args.getInteger(0); - we.checkMaxBrushRadius(radius); - - session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setSize(radius); + session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setSize(size); player.print("Brush size set."); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java new file mode 100644 index 000000000..fccc6a932 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java @@ -0,0 +1,65 @@ +/* + * 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.command.argument; + +import com.google.common.collect.ImmutableSortedSet; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +public class BooleanConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(Boolean.class), new BooleanConverter()); + } + + private static final ImmutableSortedSet TRUE = ImmutableSortedSet + .orderedBy(String.CASE_INSENSITIVE_ORDER) + .add("on", "t", "true", "y", "yes") + .build(); + + private static final ImmutableSortedSet FALSE = ImmutableSortedSet + .orderedBy(String.CASE_INSENSITIVE_ORDER) + .add("off", "f", "false", "n", "no") + .build(); + + private BooleanConverter() { + } + + @Override + public String describeAcceptableArguments() { + return "on|off|true|false"; + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + if (TRUE.contains(argument)) { + return SuccessfulConversion.fromSingle(true); + } + if (FALSE.contains(argument)) { + return SuccessfulConversion.fromSingle(false); + } + return FailedConversion.from(new IllegalArgumentException("Not a strictly boolean value: " + argument)); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java index a5fab7da3..cb91c31a6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java @@ -20,7 +20,10 @@ package com.sk89q.worldedit.command.argument; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.util.TreeGenerator; import org.enginehub.piston.CommandManager; import org.enginehub.piston.converter.ArgumentConverter; import org.enginehub.piston.converter.ConversionResult; @@ -31,34 +34,74 @@ import org.enginehub.piston.inject.Key; import javax.annotation.Nullable; import java.util.EnumSet; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Stream; + +import static com.google.common.base.Preconditions.checkState; +import static java.util.stream.Collectors.joining; public class EnumConverter> implements ArgumentConverter { public static void register(CommandManager commandManager) { commandManager.registerConverter(Key.of(SelectorChoice.class), - new EnumConverter<>(SelectorChoice.class, SelectorChoice.UNKNOWN)); + basic(SelectorChoice.class, SelectorChoice.UNKNOWN)); + commandManager.registerConverter(Key.of(TreeGenerator.TreeType.class), + full(TreeGenerator.TreeType.class, + t -> ImmutableSet.copyOf(t.lookupKeys), + null)); + commandManager.registerConverter(Key.of(EditSession.ReorderMode.class), + full(EditSession.ReorderMode.class, + r -> ImmutableSet.of(r.getDisplayName()), + null)); } + private static > EnumConverter basic(Class enumClass) { + return full(enumClass, e -> ImmutableSet.of(e.name()), null); + } + + private static > EnumConverter basic(Class enumClass, E unknownValue) { + return full(enumClass, e -> ImmutableSet.of(e.name()), unknownValue); + } + + private static > EnumConverter full(Class enumClass, + Function> lookupKeys, + @Nullable E unknownValue) { + return new EnumConverter<>(enumClass, lookupKeys, unknownValue); + } + + private final String choices; private final ImmutableMap map; @Nullable private final E unknownValue; - private EnumConverter(Class enumClass, @Nullable E unknownValue) { + private EnumConverter(Class enumClass, + Function> lookupKeys, + @Nullable E unknownValue) { ImmutableSortedMap.Builder map = ImmutableSortedMap.orderedBy(String.CASE_INSENSITIVE_ORDER); + Stream.Builder> choices = Stream.builder(); EnumSet validValues = EnumSet.allOf(enumClass); if (unknownValue != null) { validValues.remove(unknownValue); } for (E e : validValues) { - map.put(e.name(), e); + Set keys = lookupKeys.apply(e); + checkState(keys.size() > 0, "No lookup keys for enum value %s", e); + choices.add(keys); + for (String key : keys) { + map.put(key, e); + } } + this.choices = choices.build() + .map(choice -> choice.stream().collect(joining("|", "[", "]"))) + .collect(joining("|")); this.map = map.build(); this.unknownValue = unknownValue; } @Override public String describeAcceptableArguments() { - return String.join("|", map.keySet()); + return choices; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index b6c2b6c89..016500666 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -56,7 +56,12 @@ import com.sk89q.worldedit.command.SnapshotUtilCommands; import com.sk89q.worldedit.command.SnapshotUtilCommandsRegistration; import com.sk89q.worldedit.command.SuperPickaxeCommands; import com.sk89q.worldedit.command.SuperPickaxeCommandsRegistration; +import com.sk89q.worldedit.command.ToolCommands; +import com.sk89q.worldedit.command.ToolCommandsRegistration; +import com.sk89q.worldedit.command.ToolUtilCommands; +import com.sk89q.worldedit.command.ToolUtilCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; +import com.sk89q.worldedit.command.argument.BooleanConverter; import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; import com.sk89q.worldedit.command.argument.DirectionConverter; import com.sk89q.worldedit.command.argument.EnumConverter; @@ -209,6 +214,7 @@ public final class PlatformCommandMananger { EnumConverter.register(commandManager); ExpandAmountConverter.register(commandManager); ZonedDateTimeConverter.register(commandManager); + BooleanConverter.register(commandManager); } private void registerAlwaysInjectedValues() { @@ -367,14 +373,22 @@ public final class PlatformCommandMananger { SnapshotUtilCommandsRegistration.builder(), new SnapshotUtilCommands(worldEdit) ); + register( + commandManager, + ToolCommandsRegistration.builder(), + new ToolCommands(worldEdit) + ); + register( + commandManager, + ToolUtilCommandsRegistration.builder(), + new ToolUtilCommands(worldEdit) + ); // Unported commands are below. Delete once they're added to the main manager above. /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new ToolUtilCommands(worldEdit)) - .registerMethods(new ToolCommands(worldEdit)) .registerMethods(new UtilityCommands(worldEdit)) .register(adapt(new SelectionCommand(new ApplyCommand(new ReplaceParser(), "Set all blocks within selection"), "worldedit.region.set")), "/set") .group("worldedit", "we") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java index 60e5f12f3..1bd79f2ff 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.util; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; @@ -113,22 +114,22 @@ public class TreeGenerator { private static final Set primaryAliases = Sets.newHashSet(); private final String name; - private final String[] lookupKeys; + public final ImmutableList lookupKeys; static { for (TreeType type : EnumSet.allOf(TreeType.class)) { for (String key : type.lookupKeys) { lookup.put(key, type); } - if (type.lookupKeys.length > 0) { - primaryAliases.add(type.lookupKeys[0]); + if (type.lookupKeys.size() > 0) { + primaryAliases.add(type.lookupKeys.get(0)); } } } TreeType(String name, String... lookupKeys) { this.name = name; - this.lookupKeys = lookupKeys; + this.lookupKeys = ImmutableList.copyOf(lookupKeys); } public static Set getAliases() { From c05e1ed0cc7f16ac9fad486fb34cd226eb8cd830 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 25 Apr 2019 13:30:16 -0700 Subject: [PATCH 053/366] Fix a few bugs in tool commands --- .../java/com/sk89q/worldedit/command/ToolUtilCommands.java | 2 +- .../src/main/java/com/sk89q/worldedit/util/TreeGenerator.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java index 6f53cc1bf..e053eccb8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java @@ -86,7 +86,7 @@ public class ToolUtilCommands { @Command( name = "material", - aliases = { "material" }, + aliases = { "/material" }, desc = "Set the brush material" ) @CommandPermissions("worldedit.brush.options.material") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java index 1bd79f2ff..d4845c5b8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java @@ -65,8 +65,8 @@ public class TreeGenerator { } }, JUNGLE("Jungle tree", "jungle"), - SMALL_JUNGLE("Small jungle tree", "shortjungle", "smalljungle"), - SHORT_JUNGLE("Short jungle tree") { + SMALL_JUNGLE("Small jungle tree", "smalljungle"), + SHORT_JUNGLE("Short jungle tree", "shortjungle") { @Override public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException { return SMALL_JUNGLE.generate(editSession, pos); From 9b0fda9f83d7310696d9926408e7d06b0c98e3ca Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 25 Apr 2019 19:36:22 -0700 Subject: [PATCH 054/366] Port utility commands --- .../java/com/sk89q/worldedit/EditSession.java | 6 +- .../worldedit/command/UtilityCommands.java | 706 +++++++----------- .../worldedit/command/WorldEditCommands.java | 1 - .../argument/EntityRemoverConverter.java | 53 ++ .../worldedit/command/util/EntityRemover.java | 20 +- .../command/util/PrintCommandHelp.java | 160 ++++ .../platform/PlatformCommandMananger.java | 21 +- .../worldedit/util/command/CommandUtil.java | 53 ++ .../formatting/component/CommandUsageBox.java | 67 +- 9 files changed, 574 insertions(+), 513 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java 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 a831c10b8..43843e8a3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -122,7 +122,6 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; @@ -905,16 +904,15 @@ public class EditSession implements Extent, AutoCloseable { * Remove blocks of a certain type nearby a given position. * * @param position center position of cuboid - * @param blockType the block type to match + * @param mask the mask to match * @param apothem an apothem of the cuboid, where the minimum is 1 * @return number of blocks affected * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - public int removeNear(BlockVector3 position, BlockType blockType, int apothem) throws MaxChangedBlocksException { + public int removeNear(BlockVector3 position, Mask mask, int apothem) throws MaxChangedBlocksException { checkNotNull(position); checkArgument(apothem >= 1, "apothem >= 1"); - Mask mask = new BlockTypeMask(this, blockType); BlockVector3 adjustment = BlockVector3.ONE.multiply(apothem - 1); Region region = new CuboidRegion( getWorld(), // Causes clamping of Y range diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 4d69452b2..d6f916bd9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -19,28 +19,29 @@ package com.sk89q.worldedit.command; -import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CreatureButcher; import com.sk89q.worldedit.command.util.EntityRemover; import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.PrintCommandHelp; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.function.EntityFunction; +import com.sk89q.worldedit.function.mask.BlockTypeMask; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.internal.expression.Expression; @@ -50,22 +51,23 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CylinderRegion; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.session.SessionOwner; -import com.sk89q.worldedit.util.command.CommandMapping; -import com.sk89q.worldedit.util.command.Dispatcher; -import com.sk89q.worldedit.util.command.binding.Text; import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; -import org.enginehub.piston.CommandManager; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; import java.util.ArrayList; import java.util.List; -import java.util.Set; +import java.util.function.Supplier; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; /** * Utility commands. */ +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class UtilityCommands { private final WorldEdit we; @@ -75,357 +77,370 @@ public class UtilityCommands { } @Command( - aliases = { "/fill" }, - usage = " [depth]", - desc = "Fill a hole", - min = 2, - max = 3 + name = "/fill", + desc = "Fill a hole" ) @CommandPermissions("worldedit.fill") @Logging(PLACEMENT) - public void fill(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - - ParserContext context = new ParserContext(); - context.setActor(player); - context.setWorld(player.getWorld()); - context.setSession(session); - Pattern pattern = we.getPatternFactory().parseFromInput(args.getString(0), context); - - double radius = Math.max(1, args.getDouble(1)); + public int fill(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The blocks to fill with") + Pattern pattern, + @Arg(desc = "The radius to fill in") + double radius, + @Arg(desc = "The depth to fill", def = "1") + int depth) throws WorldEditException { + radius = Math.max(1, radius); we.checkMaxRadius(radius); - int depth = args.argsLength() > 2 ? Math.max(1, args.getInteger(2)) : 1; + depth = Math.max(1, depth); BlockVector3 pos = session.getPlacementPosition(player); int affected = editSession.fillXZ(pos, pattern, radius, depth, false); player.print(affected + " block(s) have been created."); + return affected; } @Command( - aliases = { "/fillr" }, - usage = " [depth]", - desc = "Fill a hole recursively", - min = 2, - max = 3 + name = "/fillr", + desc = "Fill a hole recursively" ) @CommandPermissions("worldedit.fill.recursive") @Logging(PLACEMENT) - public void fillr(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - - ParserContext context = new ParserContext(); - context.setActor(player); - context.setWorld(player.getWorld()); - context.setSession(session); - Pattern pattern = we.getPatternFactory().parseFromInput(args.getString(0), context); - - double radius = Math.max(1, args.getDouble(1)); + public int fillr(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The blocks to fill with") + Pattern pattern, + @Arg(desc = "The radius to fill in") + double radius, + @Arg(desc = "The depth to fill", def = "") + Integer depth) throws WorldEditException { + radius = Math.max(1, radius); + we.checkMaxRadius(radius); + depth = depth == null ? Integer.MAX_VALUE : Math.max(1, depth); we.checkMaxRadius(radius); - int depth = args.argsLength() > 2 ? Math.max(1, args.getInteger(2)) : Integer.MAX_VALUE; BlockVector3 pos = session.getPlacementPosition(player); - int affected = 0; - if (pattern instanceof BlockPattern) { - affected = editSession.fillXZ(pos, ((BlockPattern) pattern).getBlock(), radius, depth, true); - } else { - affected = editSession.fillXZ(pos, pattern, radius, depth, true); - } + int affected = editSession.fillXZ(pos, pattern, radius, depth, true); player.print(affected + " block(s) have been created."); + return affected; } @Command( - aliases = { "/drain" }, - usage = "", - flags = "w", - desc = "Drain a pool", - help = "Removes all connected water sources.\n" + - " If -w is specified, also makes waterlogged blocks non-waterlogged.", - min = 1, - max = 1 + name = "/drain", + desc = "Drain a pool" ) @CommandPermissions("worldedit.drain") @Logging(PLACEMENT) - public void drain(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - - double radius = Math.max(0, args.getDouble(0)); - boolean waterlogged = args.hasFlag('w'); + public int drain(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The radius to drain") + double radius, + @Switch(name = 'w', desc = "Also un-waterlog blocks") + boolean waterlogged) throws WorldEditException { + radius = Math.max(0, radius); we.checkMaxRadius(radius); int affected = editSession.drainArea( - session.getPlacementPosition(player), radius, waterlogged); + session.getPlacementPosition(player), radius, waterlogged); player.print(affected + " block(s) have been changed."); + return affected; } @Command( - aliases = { "/fixlava", "fixlava" }, - usage = "", - desc = "Fix lava to be stationary", - min = 1, - max = 1 + name = "fixlava", + aliases = { "/fixlava" }, + desc = "Fix lava to be stationary" ) @CommandPermissions("worldedit.fixlava") @Logging(PLACEMENT) - public void fixLava(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - - double radius = Math.max(0, args.getDouble(0)); + public int fixLava(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The radius to fix in") + double radius) throws WorldEditException { + radius = Math.max(0, radius); we.checkMaxRadius(radius); int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.LAVA); player.print(affected + " block(s) have been changed."); + return affected; } @Command( - aliases = { "/fixwater", "fixwater" }, - usage = "", - desc = "Fix water to be stationary", - min = 1, - max = 1 + name = "fixwater", + aliases = { "/fixwater" }, + desc = "Fix water to be stationary" ) @CommandPermissions("worldedit.fixwater") @Logging(PLACEMENT) - public void fixWater(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - - double radius = Math.max(0, args.getDouble(0)); + public int fixWater(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The radius to fix in") + double radius) throws WorldEditException { + radius = Math.max(0, radius); we.checkMaxRadius(radius); int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.WATER); player.print(affected + " block(s) have been changed."); + return affected; } @Command( - aliases = { "/removeabove", "removeabove" }, - usage = "[size] [height]", - desc = "Remove blocks above your head.", - min = 0, - max = 2 + name = "removeabove", + aliases = { "/removeabove" }, + desc = "Remove blocks above your head." ) @CommandPermissions("worldedit.removeabove") @Logging(PLACEMENT) - public void removeAbove(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - - int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; + public int removeAbove(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The apothem of the square to remove from", def = "1") + int size, + @Arg(desc = "The maximum height above you to remove from", def = "") + Integer height) throws WorldEditException { + size = Math.max(1, size); we.checkMaxRadius(size); World world = player.getWorld(); - int height = args.argsLength() > 1 ? Math.min((world.getMaxY() + 1), args.getInteger(1) + 2) : (world.getMaxY() + 1); + height = height != null ? Math.min((world.getMaxY() + 1), height + 2) : (world.getMaxY() + 1); int affected = editSession.removeAbove( - session.getPlacementPosition(player), size, height); + session.getPlacementPosition(player), size, height); player.print(affected + " block(s) have been removed."); + return affected; } @Command( - aliases = { "/removebelow", "removebelow" }, - usage = "[size] [height]", - desc = "Remove blocks below you.", - min = 0, - max = 2 + name = "removebelow", + aliases = { "/removebelow" }, + desc = "Remove blocks below you." ) @CommandPermissions("worldedit.removebelow") @Logging(PLACEMENT) - public void removeBelow(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - - int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; + public int removeBelow(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The apothem of the square to remove from", def = "1") + int size, + @Arg(desc = "The maximum height below you to remove from", def = "") + Integer height) throws WorldEditException { + size = Math.max(1, size); we.checkMaxRadius(size); World world = player.getWorld(); - int height = args.argsLength() > 1 ? Math.min((world.getMaxY() + 1), args.getInteger(1) + 2) : (world.getMaxY() + 1); + height = height != null ? Math.min((-world.getMaxY() + 1), height + 2) : (world.getMaxY() + 1); int affected = editSession.removeBelow(session.getPlacementPosition(player), size, height); player.print(affected + " block(s) have been removed."); + return affected; } @Command( - aliases = { "/removenear", "removenear" }, - usage = " [size]", - desc = "Remove blocks near you.", - min = 1, - max = 2 + name = "removenear", + aliases = { "/removenear" }, + desc = "Remove blocks near you." ) @CommandPermissions("worldedit.removenear") @Logging(PLACEMENT) - public void removeNear(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { + public int removeNear(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The mask of blocks to remove") + Mask mask, + @Arg(desc = "The radius of the square to remove from", def = "50") + int radius) throws WorldEditException { + radius = Math.max(1, radius); + we.checkMaxRadius(radius); - ParserContext context = new ParserContext(); - context.setActor(player); - context.setWorld(player.getWorld()); - context.setSession(session); - context.setRestricted(false); - context.setPreferringWildcard(false); - - BaseBlock block = we.getBlockFactory().parseFromInput(args.getString(0), context); - int size = Math.max(1, args.getInteger(1, 50)); - we.checkMaxRadius(size); - - int affected = editSession.removeNear(session.getPlacementPosition(player), block.getBlockType(), size); + int affected = editSession.removeNear(session.getPlacementPosition(player), mask, radius); player.print(affected + " block(s) have been removed."); + return affected; } @Command( - aliases = { "/replacenear", "replacenear" }, - usage = " ", - desc = "Replace nearby blocks", - flags = "f", - min = 3, - max = 3 + name = "replacenear", + aliases = { "/replacenear" }, + desc = "Replace nearby blocks" ) @CommandPermissions("worldedit.replacenear") @Logging(PLACEMENT) - public void replaceNear(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - - int size = Math.max(1, args.getInteger(0)); - we.checkMaxRadius(size); - int affected; - Set from; - Pattern to; - - ParserContext context = new ParserContext(); - context.setActor(player); - context.setWorld(player.getWorld()); - context.setSession(session); - context.setRestricted(false); - context.setPreferringWildcard(!args.hasFlag('f')); - - if (args.argsLength() == 2) { - from = null; - context.setRestricted(true); - to = we.getPatternFactory().parseFromInput(args.getString(1), context); - } else { - from = we.getBlockFactory().parseFromListInput(args.getString(1), context); - context.setRestricted(true); - to = we.getPatternFactory().parseFromInput(args.getString(2), context); - } + public int replaceNear(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The radius of the square to remove in") + int radius, + @Arg(desc = "The mask matching blocks to remove", def = "") + Mask from, + @Arg(desc = "The pattern of blocks to replace with") + Pattern to) throws WorldEditException { + radius = Math.max(1, radius); + we.checkMaxRadius(radius); BlockVector3 base = session.getPlacementPosition(player); - BlockVector3 min = base.subtract(size, size, size); - BlockVector3 max = base.add(size, size, size); + BlockVector3 min = base.subtract(radius, radius, radius); + BlockVector3 max = base.add(radius, radius, radius); Region region = new CuboidRegion(player.getWorld(), min, max); - if (to instanceof BlockPattern) { - affected = editSession.replaceBlocks(region, from, ((BlockPattern) to).getBlock()); - } else { - affected = editSession.replaceBlocks(region, from, to); + if (from == null) { + from = new ExistingBlockMask(editSession); } + + int affected = editSession.replaceBlocks(region, from, to); player.print(affected + " block(s) have been replaced."); + return affected; } @Command( - aliases = { "/snow", "snow" }, - usage = "[radius]", - desc = "Simulates snow", - min = 0, - max = 1 + name = "snow", + aliases = { "/snow" }, + desc = "Simulates snow" ) @CommandPermissions("worldedit.snow") @Logging(PLACEMENT) - public void snow(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; + public int snow(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The radius of the circle to snow in", def = "10") + double size) throws WorldEditException { + size = Math.max(1, size); we.checkMaxRadius(size); int affected = editSession.simulateSnow(session.getPlacementPosition(player), size); - player.print(affected + " surfaces covered. Let it snow~"); + player.print(affected + " surface(s) covered. Let it snow~"); + return affected; } @Command( - aliases = {"/thaw", "thaw"}, - usage = "[radius]", - desc = "Thaws the area", - min = 0, - max = 1 + name = "thaw", + aliases = { "/thaw" }, + desc = "Thaws the area" ) @CommandPermissions("worldedit.thaw") @Logging(PLACEMENT) - public void thaw(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; + public int thaw(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The radius of the circle to thaw in", def = "10") + double size) throws WorldEditException { + size = Math.max(1, size); we.checkMaxRadius(size); int affected = editSession.thaw(session.getPlacementPosition(player), size); - player.print(affected + " surfaces thawed."); + player.print(affected + " surface(s) thawed."); + return affected; } @Command( - aliases = { "/green", "green" }, - usage = "[radius]", - desc = "Greens the area", - help = "Converts dirt to grass blocks. -f also converts coarse dirt.", - flags = "f", - min = 0, - max = 1 + name = "green", + aliases = { "/green" }, + desc = "Converts dirt to grass blocks in the area" ) @CommandPermissions("worldedit.green") @Logging(PLACEMENT) - public void green(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { - final double size = args.argsLength() > 0 ? Math.max(1, args.getDouble(0)) : 10; + public int green(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The radius of the circle to convert in", def = "10") + double size, + @Switch(name = 'f', desc = "Also convert coarse dirt") + boolean convertCoarse) throws WorldEditException { + size = Math.max(1, size); we.checkMaxRadius(size); - final boolean onlyNormalDirt = !args.hasFlag('f'); + final boolean onlyNormalDirt = !convertCoarse; final int affected = editSession.green(session.getPlacementPosition(player), size, onlyNormalDirt); - player.print(affected + " surfaces greened."); + player.print(affected + " surface(s) greened."); + return affected; } @Command( - aliases = { "/ex", "/ext", "/extinguish", "ex", "ext", "extinguish" }, - usage = "[radius]", - desc = "Extinguish nearby fire", - min = 0, - max = 1 - ) + name = "extinguish", + aliases = { "/ex", "/ext", "/extinguish", "ex", "ext" }, + desc = "Extinguish nearby fire" + ) @CommandPermissions("worldedit.extinguish") @Logging(PLACEMENT) - public void extinguish(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException { + public void extinguish(Player player, LocalSession session, EditSession editSession, + @Arg(desc = "The radius of the square to remove in", def = "") + Integer radius) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40; - int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) - : defaultRadius; + int size = radius != null ? Math.max(1, radius) : defaultRadius; we.checkMaxRadius(size); - int affected = editSession.removeNear(session.getPlacementPosition(player), BlockTypes.FIRE, size); + Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE); + int affected = editSession.removeNear(session.getPlacementPosition(player), mask, size); player.print(affected + " block(s) have been removed."); } @Command( - aliases = { "butcher" }, - usage = "[radius]", - flags = "plangbtfr", - desc = "Kill all or nearby mobs", - help = - "Kills nearby mobs, based on radius, if none is given uses default in configuration.\n" + - "Flags:\n" + - " -p also kills pets.\n" + - " -n also kills NPCs.\n" + - " -g also kills Golems.\n" + - " -a also kills animals.\n" + - " -b also kills ambient mobs.\n" + - " -t also kills mobs with name tags.\n" + - " -f compounds all previous flags.\n" + - " -r also destroys armor stands.\n" + - " -l currently does nothing.", - min = 0, - max = 1 + name = "butcher", + desc = "Kill all or nearby mobs" ) @CommandPermissions("worldedit.butcher") @Logging(PLACEMENT) - public void butcher(Actor actor, CommandContext args) throws WorldEditException { + public int butcher(Actor actor, + @Arg(desc = "Radius to kill mobs in", def = "") + Integer radius, + @Switch(name = 'p', desc = "Also kill pets") + boolean killPets, + @Switch(name = 'n', desc = "Also kill NPCs") + boolean killNpcs, + @Switch(name = 'g', desc = "Also kill golems") + boolean killGolems, + @Switch(name = 'a', desc = "Also kill animals") + boolean killAnimals, + @Switch(name = 'b', desc = "Also kill ambient mobs") + boolean killAmbient, + @Switch(name = 't', desc = "Also kill mobs with name tags") + boolean killWithName, + @Switch(name = 'f', desc = "Also kill all friendly mobs (Applies the flags `-abgnpt`)") + boolean killFriendly, + @Switch(name = 'r', desc = "Also destroy armor stands") + boolean killArmorStands, + @Switch(name = 'l', desc = "Kill via lightning. Currently non-functioning.") + boolean killWithLightning) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); Player player = actor instanceof Player ? (Player) actor : null; - // technically the default can be larger than the max, but that's not my problem - int radius = config.butcherDefaultRadius; - - // there might be a better way to do this but my brain is fried right now - if (args.argsLength() > 0) { // user inputted radius, override the default - radius = args.getInteger(0); - if (radius < -1) { - actor.printError("Use -1 to remove all mobs in loaded chunks"); - return; - } - if (config.butcherMaxRadius != -1) { // clamp if there is a max - if (radius == -1) { - radius = config.butcherMaxRadius; - } else { // Math.min does not work if radius is -1 (actually highest possible value) - radius = Math.min(radius, config.butcherMaxRadius); - } + int defaultRadius = config.butcherDefaultRadius; + if (radius == null) { + radius = config.butcherDefaultRadius; + } else if (radius < -1) { + actor.printError("Use -1 to remove all mobs in loaded chunks"); + return 0; + } else if (radius == -1) { + if (config.butcherMaxRadius != -1) { + radius = config.butcherMaxRadius; } } + if (config.butcherMaxRadius != -1) { + radius = Math.min(radius, config.butcherMaxRadius); + } CreatureButcher flags = new CreatureButcher(actor); - flags.fromCommand(args); + flags.or(CreatureButcher.Flags.FRIENDLY, killFriendly); // No permission check here. Flags will instead be filtered by the subsequent calls. + flags.or(CreatureButcher.Flags.PETS, killPets, "worldedit.butcher.pets"); + flags.or(CreatureButcher.Flags.NPCS, killNpcs, "worldedit.butcher.npcs"); + flags.or(CreatureButcher.Flags.GOLEMS, killGolems, "worldedit.butcher.golems"); + flags.or(CreatureButcher.Flags.ANIMALS, killAnimals, "worldedit.butcher.animals"); + flags.or(CreatureButcher.Flags.AMBIENT, killAmbient, "worldedit.butcher.ambient"); + flags.or(CreatureButcher.Flags.TAGGED, killWithName, "worldedit.butcher.tagged"); + flags.or(CreatureButcher.Flags.ARMOR_STAND, killArmorStands, "worldedit.butcher.armorstands"); + flags.or(CreatureButcher.Flags.WITH_LIGHTNING, killWithLightning, "worldedit.butcher.lightning"); + + int killed = killMatchingEntities(radius, player, flags::createFunction); + + actor.print("Killed " + killed + (killed != 1 ? " mobs" : " mob") + (radius < 0 ? "" : " in a radius of " + radius) + "."); + + return killed; + } + + @Command( + name = "remove", + aliases = { "rem", "rement" }, + desc = "Remove all entities of a type" + ) + @CommandPermissions("worldedit.remove") + @Logging(PLACEMENT) + public int remove(Actor actor, + @Arg(desc = "The type of entity to remove") + EntityRemover remover, + @Arg(desc = "The radius of the cuboid to remove from") + int radius) throws WorldEditException { + Player player = actor instanceof Player ? (Player) actor : null; + + if (radius < -1) { + actor.printError("Use -1 to remove all entities in loaded chunks"); + return 0; + } + + int removed = killMatchingEntities(radius, player, remover::createFunction); + + actor.print("Marked " + removed + (removed != 1 ? " entities" : " entity") + " for removal."); + return removed; + } + + private int killMatchingEntities(Integer radius, Player player, Supplier func) throws IncompleteRegionException, MaxChangedBlocksException { List visitors = new ArrayList<>(); LocalSession session = null; EditSession editSession = null; @@ -441,12 +456,12 @@ public class UtilityCommands { } else { entities = editSession.getEntities(); } - visitors.add(new EntityVisitor(entities.iterator(), flags.createFunction())); + visitors.add(new EntityVisitor(entities.iterator(), func.get())); } else { Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING); for (World world : platform.getWorlds()) { List entities = world.getEntities(); - visitors.add(new EntityVisitor(entities.iterator(), flags.createFunction())); + visitors.add(new EntityVisitor(entities.iterator(), func.get())); } } @@ -456,246 +471,47 @@ public class UtilityCommands { killed += visitor.getAffected(); } - actor.print("Killed " + killed + (killed != 1 ? " mobs" : " mob") + (radius < 0 ? "" : " in a radius of " + radius) + "."); - if (editSession != null) { session.remember(editSession); editSession.flushSession(); } + return killed; } @Command( - aliases = { "remove", "rem", "rement" }, - usage = " ", - desc = "Remove all entities of a type", - min = 2, - max = 2 - ) - @CommandPermissions("worldedit.remove") - @Logging(PLACEMENT) - public void remove(Actor actor, CommandContext args) throws WorldEditException, CommandException { - String typeStr = args.getString(0); - int radius = args.getInteger(1); - Player player = actor instanceof Player ? (Player) actor : null; - - if (radius < -1) { - actor.printError("Use -1 to remove all entities in loaded chunks"); - return; - } - - EntityRemover remover = new EntityRemover(); - remover.fromString(typeStr); - - List visitors = new ArrayList<>(); - LocalSession session = null; - EditSession editSession = null; - - if (player != null) { - session = we.getSessionManager().get(player); - BlockVector3 center = session.getPlacementPosition(player); - editSession = session.createEditSession(player); - List entities; - if (radius >= 0) { - CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius); - entities = editSession.getEntities(region); - } else { - entities = editSession.getEntities(); - } - visitors.add(new EntityVisitor(entities.iterator(), remover.createFunction())); - } else { - Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING); - for (World world : platform.getWorlds()) { - List entities = world.getEntities(); - visitors.add(new EntityVisitor(entities.iterator(), remover.createFunction())); - } - } - - int removed = 0; - for (EntityVisitor visitor : visitors) { - Operations.completeLegacy(visitor); - removed += visitor.getAffected(); - } - - actor.print("Marked " + removed + (removed != 1 ? " entities" : " entity") + " for removal."); - - if (editSession != null) { - session.remember(editSession); - editSession.flushSession(); - } - } - - @Command( - aliases = { "/calc", "/calculate", "/eval", "/evaluate", "/solve" }, - usage = "", + name = "/calculate", + aliases = { "/calc", "/eval", "/evaluate", "/solve" }, desc = "Evaluate a mathematical expression" ) @CommandPermissions("worldedit.calc") - public void calc(Actor actor, @Text String input) throws CommandException { + public void calc(Actor actor, + @Arg(desc = "Expression to evaluate") + String input) { try { Expression expression = Expression.compile(input); - if (actor instanceof SessionOwner) { - actor.print("= " + expression.evaluate( - new double[]{}, WorldEdit.getInstance().getSessionManager().get((SessionOwner) actor).getTimeout())); - } else { - actor.print("= " + expression.evaluate()); - } + actor.print("= " + expression.evaluate( + new double[] {}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout())); } catch (EvaluationException e) { actor.printError(String.format( - "'%s' could not be evaluated (error: %s)", input, e.getMessage())); + "'%s' could not be evaluated (error: %s)", input, e.getMessage())); } catch (ExpressionException e) { actor.printError(String.format( - "'%s' could not be parsed as a valid expression", input)); + "'%s' could not be parsed as a valid expression", input)); } } @Command( - aliases = { "/help" }, - usage = "[]", - desc = "Displays help for WorldEdit commands", - min = 0, - max = -1 + name = "/help", + desc = "Displays help for WorldEdit commands" ) @CommandPermissions("worldedit.help") - public void help(Actor actor, CommandContext args) throws WorldEditException { - help(args, we, actor); + public void help(Actor actor, + @Arg(desc = "The page to retrieve", def = "1") + int page, + @Arg(desc = "The command to retrieve help for", def = "", variable = true) + List commandPath) throws WorldEditException { + PrintCommandHelp.help(commandPath, page, we, actor); } - private static CommandMapping detectCommand(Dispatcher dispatcher, String command, boolean isRootLevel) { - CommandMapping mapping; - - // First try the command as entered - mapping = dispatcher.get(command); - if (mapping != null) { - return mapping; - } - - // Then if we're looking at root commands and the user didn't use - // any slashes, let's try double slashes and then single slashes. - // However, be aware that there exists different single slash - // and double slash commands in WorldEdit - if (isRootLevel && !command.contains("/")) { - mapping = dispatcher.get("//" + command); - if (mapping != null) { - return mapping; - } - - mapping = dispatcher.get("/" + command); - if (mapping != null) { - return mapping; - } - } - - return null; - } - - public static void help(CommandContext args, WorldEdit we, Actor actor) { - CommandManager manager = we.getPlatformManager().getPlatformCommandMananger().getCommandManager(); - - // TODO this will be implemented as a special utility in the manager - /* - - int page = 0; - final int perPage = actor instanceof Player ? 8 : 20; // More pages for console - int effectiveLength = args.argsLength(); - - // Detect page from args - try { - if (args.argsLength() > 0) { - page = args.getInteger(args.argsLength() - 1); - if (page <= 0) { - page = 1; - } else { - page--; - } - - effectiveLength--; - } - } catch (NumberFormatException ignored) { - } - - boolean isRootLevel = true; - List visited = new ArrayList<>(); - - // Drill down to the command - for (int i = 0; i < effectiveLength; i++) { - String command = args.getString(i); - - if (manager instanceof Dispatcher) { - // Chop off the beginning / if we're are the root level - if (isRootLevel && command.length() > 1 && command.charAt(0) == '/') { - command = command.substring(1); - } - - CommandMapping mapping = detectCommand((Dispatcher) manager, command, isRootLevel); - if (mapping != null) { - manager = mapping.getCallable(); - } else { - if (isRootLevel) { - actor.printError(String.format("The command '%s' could not be found.", args.getString(i))); - return; - } else { - actor.printError(String.format("The sub-command '%s' under '%s' could not be found.", - command, Joiner.on(" ").join(visited))); - return; - } - } - - visited.add(args.getString(i)); - isRootLevel = false; - } else { - actor.printError(String.format("'%s' has no sub-commands. (Maybe '%s' is for a parameter?)", - Joiner.on(" ").join(visited), command)); - return; - } - } - - // Create the message - if (manager instanceof Dispatcher) { - Dispatcher dispatcher = (Dispatcher) manager; - - // Get a list of aliases - List aliases = new ArrayList<>(dispatcher.getCommands()); - aliases.sort(new PrimaryAliasComparator(PlatformCommandMananger.COMMAND_CLEAN_PATTERN)); - - // Calculate pagination - int offset = perPage * page; - int pageTotal = (int) Math.ceil(aliases.size() / (double) perPage); - - // Box - CommandListBox box = new CommandListBox(String.format("Help: page %d/%d ", page + 1, pageTotal)); - StyledFragment contents = box.getContents(); - StyledFragment tip = contents.createFragment(Style.GRAY); - - if (offset >= aliases.size()) { - tip.createFragment(Style.RED).append(String.format("There is no page %d (total number of pages is %d).", page + 1, pageTotal)).newLine(); - } else { - List list = aliases.subList(offset, Math.min(offset + perPage, aliases.size())); - - tip.append("Type "); - tip.append(new Code().append("//help ").append(" []")); - tip.append(" for more information.").newLine(); - - // Add each command - for (CommandMapping mapping : list) { - StringBuilder builder = new StringBuilder(); - if (isRootLevel) { - builder.append("/"); - } - if (!visited.isEmpty()) { - builder.append(Joiner.on(" ").join(visited)); - builder.append(" "); - } - builder.append(mapping.getPrimaryAlias()); - box.appendCommand(builder.toString(), mapping.getDescription().getDescription()); - } - } - - actor.printRaw(ColorCodeBuilder.asColorCodes(box)); - } else { - CommandUsageBox box = new CommandUsageBox(manager, Joiner.on(" ").join(visited)); - actor.printRaw(ColorCodeBuilder.asColorCodes(box)); - } - */ - } } 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 5378d5819..aee7ba0f7 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 @@ -157,6 +157,5 @@ public class WorldEditCommands { ) @CommandPermissions("worldedit.help") public void help(Actor actor, CommandContext args) throws WorldEditException { - UtilityCommands.help(args, we, actor); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java new file mode 100644 index 000000000..03db41b28 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java @@ -0,0 +1,53 @@ +/* + * 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.command.argument; + +import com.sk89q.worldedit.command.util.EntityRemover; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +public class EntityRemoverConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(EntityRemover.class), new EntityRemoverConverter()); + } + + private EntityRemoverConverter() { + } + + @Override + public String describeAcceptableArguments() { + return "projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"; + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + try { + return SuccessfulConversion.fromSingle(EntityRemover.fromString(argument)); + } catch (Exception e) { + return FailedConversion.from(e); + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java index cac57b0dc..516f33945 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/EntityRemover.java @@ -19,15 +19,13 @@ package com.sk89q.worldedit.command.util; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.worldedit.entity.metadata.EntityProperties; import com.sk89q.worldedit.function.EntityFunction; +import javax.annotation.Nullable; import java.util.regex.Pattern; -import javax.annotation.Nullable; +import static com.google.common.base.Preconditions.checkNotNull; /** * The implementation of /remove. @@ -125,17 +123,21 @@ public class EntityRemover { } } - private Type type; - - public void fromString(String str) throws CommandException { + public static EntityRemover fromString(String str) { Type type = Type.findByPattern(str); if (type != null) { - this.type = type; + return new EntityRemover(type); } else { - throw new CommandException("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"); + throw new IllegalArgumentException("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"); } } + private final Type type; + + private EntityRemover(Type type) { + this.type = type; + } + public EntityFunction createFunction() { final Type type = this.type; checkNotNull(type, "type can't be null"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java new file mode 100644 index 000000000..c22880f04 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -0,0 +1,160 @@ +/* + * 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.command.util; + +import com.google.common.base.Joiner; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.formatting.ColorCodeBuilder; +import com.sk89q.worldedit.util.formatting.Style; +import com.sk89q.worldedit.util.formatting.StyledFragment; +import com.sk89q.worldedit.util.formatting.component.Code; +import com.sk89q.worldedit.util.formatting.component.CommandListBox; +import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +import static com.sk89q.worldedit.util.command.CommandUtil.byCleanName; +import static com.sk89q.worldedit.util.command.CommandUtil.getSubCommands; +import static java.util.stream.Collectors.toList; + +/** + * Implementation of the //help command. + */ +// Stored in a separate class to prevent import conflicts. +public class PrintCommandHelp { + + private static Command detectCommand(CommandManager manager, String command) { + Optional mapping; + + // First try the command as entered + mapping = manager.getCommand(command); + if (mapping.isPresent()) { + return mapping.get(); + } + + // If tried with slashes, try dropping a slash + if (command.startsWith("/")) { + mapping = manager.getCommand(command.substring(1)); + return mapping.orElse(null); + } + + // Otherwise, check /command, since that's common + mapping = manager.getCommand("/" + command); + return mapping.orElse(null); + } + + public static void help(List commandPath, int page, WorldEdit we, Actor actor) { + if (page < 1) { + actor.printError("Page must be >= 1."); + return; + } + CommandManager manager = we.getPlatformManager().getPlatformCommandMananger().getCommandManager(); + + final int perPage = actor instanceof Player ? 8 : 20; // More pages for console + + if (commandPath.isEmpty()) { + printAllCommands(page, perPage, manager.getAllCommands(), actor, true); + return; + } + + List visited = new ArrayList<>(); + Command currentCommand = detectCommand(manager, commandPath.get(0)); + if (currentCommand == null) { + actor.printError(String.format("The command '%s' could not be found.", commandPath.get(0))); + return; + } + visited.add(commandPath.get(0)); + + // Drill down to the command + for (int i = 1; i < commandPath.size(); i++) { + String subCommand = commandPath.get(i); + Map subCommands = getSubCommands(currentCommand); + + if (subCommands.isEmpty()) { + actor.printError(String.format("'%s' has no sub-commands. (Maybe '%s' is for a parameter?)", + Joiner.on(" ").join(visited), subCommand)); + return; + } + + if (subCommands.containsKey(subCommand)) { + visited.add(subCommand); + currentCommand = subCommands.get(subCommand); + } else { + actor.printError(String.format("The sub-command '%s' under '%s' could not be found.", + subCommand, Joiner.on(" ").join(visited))); + return; + } + } + + Map subCommands = getSubCommands(currentCommand); + + if (subCommands.isEmpty()) { + // Create the message + CommandUsageBox box = new CommandUsageBox(currentCommand, String.join(" ", visited)); + actor.printRaw(ColorCodeBuilder.asColorCodes(box)); + } else { + printAllCommands(page, perPage, subCommands.values().stream(), actor, false); + } + } + + private static void printAllCommands(int page, int perPage, Stream commandStream, Actor actor, boolean isRootLevel) { + // Get a list of aliases + List commands = commandStream + .sorted(byCleanName()) + .collect(toList()); + + // Calculate pagination + int offset = perPage * (page - 1); + int pageTotal = (int) Math.ceil(commands.size() / (double) perPage); + + // Box + CommandListBox box = new CommandListBox(String.format("Help: page %d/%d ", page, pageTotal)); + StyledFragment contents = box.getContents(); + StyledFragment tip = contents.createFragment(Style.GRAY); + + if (offset >= commands.size()) { + tip.createFragment(Style.RED).append(String.format("There is no page %d (total number of pages is %d).", page, pageTotal)).newLine(); + } else { + List list = commands.subList(offset, Math.min(offset + perPage, commands.size())); + + tip.append("Type "); + tip.append(new Code().append("//help ").append("[] ")); + tip.append(" for more information.").newLine(); + + // Add each command + for (Command mapping : list) { + box.appendCommand((isRootLevel ? "/" : "") + mapping.getName(), mapping.getDescription()); + } + } + + actor.printRaw(ColorCodeBuilder.asColorCodes(box)); + } + + private PrintCommandHelp() { + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 016500666..25266047f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -60,10 +60,13 @@ import com.sk89q.worldedit.command.ToolCommands; import com.sk89q.worldedit.command.ToolCommandsRegistration; import com.sk89q.worldedit.command.ToolUtilCommands; import com.sk89q.worldedit.command.ToolUtilCommandsRegistration; +import com.sk89q.worldedit.command.UtilityCommands; +import com.sk89q.worldedit.command.UtilityCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.argument.BooleanConverter; import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; import com.sk89q.worldedit.command.argument.DirectionConverter; +import com.sk89q.worldedit.command.argument.EntityRemoverConverter; import com.sk89q.worldedit.command.argument.EnumConverter; import com.sk89q.worldedit.command.argument.ExpandAmountConverter; import com.sk89q.worldedit.command.argument.MaskConverter; @@ -78,16 +81,11 @@ import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.annotation.Selection; -import com.sk89q.worldedit.internal.command.ActorAuthorizer; import com.sk89q.worldedit.internal.command.CommandLoggingHandler; -import com.sk89q.worldedit.internal.command.UserCommandCompleter; -import com.sk89q.worldedit.internal.command.WorldEditBinding; import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; -import com.sk89q.worldedit.util.command.parametric.LegacyCommandsHandler; -import com.sk89q.worldedit.util.command.parametric.ParametricBuilder; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; @@ -188,12 +186,6 @@ public final class PlatformCommandMananger { commandLog.addHandler(dynamicHandler); // Set up the commands manager - ParametricBuilder builder = new ParametricBuilder(); - builder.setAuthorizer(new ActorAuthorizer()); - builder.setDefaultCompleter(new UserCommandCompleter(platformManager)); - builder.addBinding(new WorldEditBinding(worldEdit)); - builder.addInvokeListener(new LegacyCommandsHandler()); - registerAlwaysInjectedValues(); registerArgumentConverters(); registerAllCommands(); @@ -215,6 +207,7 @@ public final class PlatformCommandMananger { ExpandAmountConverter.register(commandManager); ZonedDateTimeConverter.register(commandManager); BooleanConverter.register(commandManager); + EntityRemoverConverter.register(commandManager); } private void registerAlwaysInjectedValues() { @@ -383,13 +376,17 @@ public final class PlatformCommandMananger { ToolUtilCommandsRegistration.builder(), new ToolUtilCommands(worldEdit) ); + register( + commandManager, + UtilityCommandsRegistration.builder(), + new UtilityCommands(worldEdit) + ); // Unported commands are below. Delete once they're added to the main manager above. /* dispatcher = new CommandGraph() .builder(builder) .commands() - .registerMethods(new UtilityCommands(worldEdit)) .register(adapt(new SelectionCommand(new ApplyCommand(new ReplaceParser(), "Set all blocks within selection"), "worldedit.region.set")), "/set") .group("worldedit", "we") .describeAs("WorldEdit commands") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java new file mode 100644 index 000000000..c583add43 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java @@ -0,0 +1,53 @@ +/* + * 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.util.command; + +import com.sk89q.worldedit.extension.platform.PlatformCommandMananger; +import org.enginehub.piston.Command; +import org.enginehub.piston.part.SubCommandPart; + +import java.util.Comparator; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class CommandUtil { + + public static Map getSubCommands(Command currentCommand) { + return currentCommand.getParts().stream() + .filter(p -> p instanceof SubCommandPart) + .flatMap(p -> ((SubCommandPart) p).getCommands().stream()) + .collect(Collectors.toMap(Command::getName, Function.identity())); + } + + private static String clean(String input) { + return PlatformCommandMananger.COMMAND_CLEAN_PATTERN.matcher(input).replaceAll(""); + } + + private static final Comparator BY_CLEAN_NAME = + Comparator.comparing(c -> clean(c.getName())); + + public static Comparator byCleanName() { + return BY_CLEAN_NAME; + } + + private CommandUtil() { + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index c7c5cf40d..03c01bf2a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -19,21 +19,18 @@ package com.sk89q.worldedit.util.formatting.component; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.extension.platform.PlatformCommandMananger; -import com.sk89q.worldedit.util.command.CommandCallable; -import com.sk89q.worldedit.util.command.CommandMapping; -import com.sk89q.worldedit.util.command.Description; -import com.sk89q.worldedit.util.command.Dispatcher; -import com.sk89q.worldedit.util.command.PrimaryAliasComparator; import com.sk89q.worldedit.util.formatting.StyledFragment; - -import java.util.ArrayList; -import java.util.List; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandParameters; import javax.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.util.command.CommandUtil.byCleanName; +import static com.sk89q.worldedit.util.command.CommandUtil.getSubCommands; /** * A box to describe usage of a command. @@ -46,7 +43,7 @@ public class CommandUsageBox extends StyledFragment { * @param command the command to describe * @param commandString the command that was used, such as "/we" or "/brush sphere" */ - public CommandUsageBox(CommandCallable command, String commandString) { + public CommandUsageBox(Command command, String commandString) { this(command, commandString, null); } @@ -55,54 +52,40 @@ public class CommandUsageBox extends StyledFragment { * * @param command the command to describe * @param commandString the command that was used, such as "/we" or "/brush sphere" - * @param locals list of locals to use + * @param parameters list of parameters to use */ - public CommandUsageBox(CommandCallable command, String commandString, @Nullable CommandLocals locals) { + public CommandUsageBox(Command command, String commandString, @Nullable CommandParameters parameters) { checkNotNull(command); checkNotNull(commandString); - if (command instanceof Dispatcher) { - attachDispatcherUsage((Dispatcher) command, commandString, locals); + Map subCommands = getSubCommands(command); + if (subCommands.isEmpty()) { + attachCommandUsage(command, commandString); } else { - attachCommandUsage(command.getDescription(), commandString); + attachSubcommandUsage(subCommands, commandString, parameters); } } - private void attachDispatcherUsage(Dispatcher dispatcher, String commandString, @Nullable CommandLocals locals) { + private void attachSubcommandUsage(Map dispatcher, String commandString, @Nullable CommandParameters parameters) { CommandListBox box = new CommandListBox("Subcommands"); String prefix = !commandString.isEmpty() ? commandString + " " : ""; - List list = new ArrayList<>(dispatcher.getCommands()); - list.sort(new PrimaryAliasComparator(PlatformCommandMananger.COMMAND_CLEAN_PATTERN)); + List list = dispatcher.values().stream() + .sorted(byCleanName()) + .collect(Collectors.toList()); - for (CommandMapping mapping : list) { - if (locals == null || mapping.getCallable().testPermission(locals)) { - box.appendCommand(prefix + mapping.getPrimaryAlias(), mapping.getDescription().getDescription()); + for (Command mapping : list) { + if (parameters == null || mapping.getCondition().satisfied(parameters)) { + box.appendCommand(prefix + mapping.getName(), mapping.getDescription()); } } append(box); } - private void attachCommandUsage(Description description, String commandString) { + private void attachCommandUsage(Command description, String commandString) { MessageBox box = new MessageBox("Help for " + commandString); - StyledFragment contents = box.getContents(); - if (description.getUsage() != null) { - contents.append(new Label().append("Usage: ")); - contents.append(description.getUsage()); - } else { - contents.append(new Subtle().append("Usage information is not available.")); - } - - contents.newLine(); - - if (description.getHelp() != null) { - contents.append(description.getHelp()); - } else if (description.getDescription() != null) { - contents.append(description.getDescription()); - } else { - contents.append(new Subtle().append("No further help is available.")); - } + box.getContents().append(description.getFullHelp()); append(box); } From d8290cbd8f5391cc4e248a8b14674b6b9a9239ec Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 25 Apr 2019 21:03:28 -0700 Subject: [PATCH 055/366] Port worldedit commands --- .../worldedit/command/UtilityCommands.java | 4 +- .../worldedit/command/WorldEditCommands.java | 72 ++++++++++--------- .../platform/PlatformCommandMananger.java | 29 +++++--- 3 files changed, 60 insertions(+), 45 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index d6f916bd9..dae704efc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -509,8 +509,8 @@ public class UtilityCommands { @Arg(desc = "The page to retrieve", def = "1") int page, @Arg(desc = "The command to retrieve help for", def = "", variable = true) - List commandPath) throws WorldEditException { - PrintCommandHelp.help(commandPath, page, we, actor); + List command) throws WorldEditException { + PrintCommandHelp.help(command, page, we, actor); } 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 aee7ba0f7..1b7346cd0 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 @@ -20,12 +20,12 @@ package com.sk89q.worldedit.command; import com.google.common.io.Files; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.PrintCommandHelp; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent; import com.sk89q.worldedit.extension.platform.Actor; @@ -36,6 +36,10 @@ import com.sk89q.worldedit.util.paste.ActorCallbackPaste; import com.sk89q.worldedit.util.report.ConfigReport; import com.sk89q.worldedit.util.report.ReportList; import com.sk89q.worldedit.util.report.SystemInfoReport; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.Switch; import java.io.File; import java.io.IOException; @@ -44,8 +48,10 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.TextStyle; +import java.util.List; import java.util.Locale; +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class WorldEditCommands { private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z"); @@ -56,11 +62,9 @@ public class WorldEditCommands { } @Command( - aliases = { "version", "ver" }, - usage = "", - desc = "Get WorldEdit version", - min = 0, - max = 0 + name = "version", + aliases = { "ver" }, + desc = "Get WorldEdit version" ) public void version(Actor actor) throws WorldEditException { actor.print("WorldEdit version " + WorldEdit.getVersion()); @@ -81,11 +85,8 @@ public class WorldEditCommands { } @Command( - aliases = { "reload" }, - usage = "", - desc = "Reload configuration", - min = 0, - max = 0 + name = "reload", + desc = "Reload configuration" ) @CommandPermissions("worldedit.reload") public void reload(Actor actor) throws WorldEditException { @@ -94,9 +95,14 @@ public class WorldEditCommands { actor.print("Configuration reloaded!"); } - @Command(aliases = {"report"}, desc = "Writes a report on WorldEdit", flags = "p", max = 0) + @Command( + name = "report", + desc = "Writes a report on WorldEdit" + ) @CommandPermissions({"worldedit.report"}) - public void report(Actor actor, CommandContext args) throws WorldEditException { + public void report(Actor actor, + @Switch(name = 'p', desc = "Pastebins the report") + boolean pastebin) throws WorldEditException { ReportList report = new ReportList("Report"); report.add(new SystemInfoReport()); report.add(new ConfigReport()); @@ -110,7 +116,7 @@ public class WorldEditCommands { actor.printError("Failed to write report: " + e.getMessage()); } - if (args.hasFlag('p')) { + if (pastebin) { actor.checkPermission("worldedit.report.pastebin"); ActorCallbackPaste.pastebin( we.getSupervisor(), actor, result, "WorldEdit report: %s.report", @@ -120,11 +126,8 @@ public class WorldEditCommands { } @Command( - aliases = { "cui" }, - usage = "", - desc = "Complete CUI handshake (internal usage)", - min = 0, - max = 0 + name = "cui", + desc = "Complete CUI handshake (internal usage)" ) public void cui(Player player, LocalSession session) throws WorldEditException { session.setCUISupport(true); @@ -132,14 +135,13 @@ public class WorldEditCommands { } @Command( - aliases = { "tz" }, - usage = "[timezone]", - desc = "Set your timezone for snapshots", - min = 1, - max = 1 + name = "tz", + desc = "Set your timezone for snapshots" ) - public void tz(Player player, LocalSession session, CommandContext args) throws WorldEditException { - ZoneId tz = ZoneId.of(args.getString(0)); + public void tz(Player player, LocalSession session, + @Arg(desc = "The timezone to set") + String timezone) throws WorldEditException { + ZoneId tz = ZoneId.of(timezone); session.setTimezone(tz); player.print("Timezone set for this session to: " + tz.getDisplayName( TextStyle.FULL, Locale.ENGLISH @@ -149,13 +151,15 @@ public class WorldEditCommands { } @Command( - aliases = { "help" }, - usage = "[]", - desc = "Displays help for WorldEdit commands", - min = 0, - max = -1 + name = "help", + desc = "Displays help for WorldEdit commands" ) @CommandPermissions("worldedit.help") - public void help(Actor actor, CommandContext args) throws WorldEditException { + public void help(Actor actor, + @Arg(desc = "The page to retrieve", def = "1") + int page, + @Arg(desc = "The command to retrieve help for", def = "", variable = true) + List command) throws WorldEditException { + PrintCommandHelp.help(command, page, we, actor); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index 25266047f..998371d0b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -62,6 +62,8 @@ import com.sk89q.worldedit.command.ToolUtilCommands; import com.sk89q.worldedit.command.ToolUtilCommandsRegistration; import com.sk89q.worldedit.command.UtilityCommands; import com.sk89q.worldedit.command.UtilityCommandsRegistration; +import com.sk89q.worldedit.command.WorldEditCommands; +import com.sk89q.worldedit.command.WorldEditCommandsRegistration; import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.argument.BooleanConverter; import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; @@ -311,6 +313,24 @@ public final class PlatformCommandMananger { .required() .build()); }); + commandManager.register("worldedit", cmd -> { + cmd.aliases(ImmutableList.of("we")); + cmd.description("WorldEdit commands"); + cmd.action(Command.Action.NULL_ACTION); + + CommandManager manager = DefaultCommandManagerService.getInstance() + .newCommandManager(); + register( + manager, + WorldEditCommandsRegistration.builder(), + new WorldEditCommands(worldEdit) + ); + + cmd.addPart(SubCommandPart.builder("action", "Sub-command to run.") + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() + .build()); + }); register( commandManager, BiomeCommandsRegistration.builder(), @@ -388,10 +408,6 @@ public final class PlatformCommandMananger { .builder(builder) .commands() .register(adapt(new SelectionCommand(new ApplyCommand(new ReplaceParser(), "Set all blocks within selection"), "worldedit.region.set")), "/set") - .group("worldedit", "we") - .describeAs("WorldEdit commands") - .registerMethods(new WorldEditCommands(worldEdit)) - .parent() .group("brush", "br") .describeAs("Brushing commands") .register(adapt(new ShapedBrushCommand(new DeformCommand(), "worldedit.brush.deform")), "deform") @@ -402,11 +418,6 @@ public final class PlatformCommandMananger { .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y-=1", Mode.RAW_COORD), "Raise one block"), "worldedit.brush.raise")), "raise") .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y+=1", Mode.RAW_COORD), "Lower one block"), "worldedit.brush.lower")), "lower") .parent() - .group("tool") - .describeAs("Bind functions to held items") - .registerMethods(new ToolCommands(worldEdit)) - .parent() - .graph() .getDispatcher(); */ } From 8348ffa7cf267b5ea86504ff8c6cce9c0ce7f233 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 25 Apr 2019 22:54:23 -0700 Subject: [PATCH 056/366] Drop translatable names for now --- worldedit-core/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index 6724db672..9ed0f8b2a 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -35,6 +35,10 @@ dependencies { testCompile 'org.mockito:mockito-core:1.9.0-rc1' } +tasks.withType(JavaCompile).configureEach { + it.options.compilerArgs.add("-Aarg.name.key.prefix=") +} + sourceSets { main { java { From 2486388e18432a4235e2da292adb28e61dda0683 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 25 Apr 2019 23:02:23 -0700 Subject: [PATCH 057/366] Fix help command suggestion --- .../worldedit/command/util/PrintCommandHelp.java | 14 ++++++++++---- .../util/formatting/component/CommandListBox.java | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java index 48f835a61..57337b322 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.command.util; import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; @@ -35,6 +36,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.Stream; import static com.sk89q.worldedit.util.command.CommandUtil.byCleanName; @@ -77,7 +79,7 @@ public class PrintCommandHelp { final int perPage = actor instanceof Player ? 8 : 20; // More pages for console if (commandPath.isEmpty()) { - printAllCommands(page, perPage, manager.getAllCommands(), actor, true); + printAllCommands(page, perPage, manager.getAllCommands(), actor, ImmutableList.of()); return; } @@ -117,11 +119,12 @@ public class PrintCommandHelp { CommandUsageBox box = new CommandUsageBox(currentCommand, String.join(" ", visited)); actor.print(box.create()); } else { - printAllCommands(page, perPage, subCommands.values().stream(), actor, false); + printAllCommands(page, perPage, subCommands.values().stream(), actor, visited); } } - private static void printAllCommands(int page, int perPage, Stream commandStream, Actor actor, boolean isRootLevel) { + private static void printAllCommands(int page, int perPage, Stream commandStream, Actor actor, + List commandList) { // Get a list of aliases List commands = commandStream .sorted(byCleanName()) @@ -147,7 +150,10 @@ public class PrintCommandHelp { // Add each command for (Command mapping : list) { - box.appendCommand((isRootLevel ? "/" : "") + mapping.getName(), mapping.getDescription()); + String alias = (commandList.isEmpty() ? "/" : "") + mapping.getName(); + String command = Stream.concat(commandList.stream(), Stream.of(mapping.getName())) + .collect(Collectors.joining(" ", "/", "")); + box.appendCommand(alias, mapping.getDescription(), command); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java index c049006b6..f39a74656 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -53,7 +53,7 @@ public class CommandListBox extends MessageBox { TextComponent commandName = TextComponent.of(alias, TextColor.GOLD); if (insertion != null) { commandName = commandName - .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, insertion)) + .clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, insertion)) .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select"))); } getContents().append(commandName.append(TextComponent.of(": "))); From 46e0a7ba48d517cb49cab8ceae8b8c94f0a3f04d Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 25 Apr 2019 23:16:18 -0700 Subject: [PATCH 058/366] Port //set --- .../worldedit/command/RegionCommands.java | 30 +++++++++++++++++++ .../platform/PlatformCommandMananger.java | 1 - 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 6c5bcbfc2..ae4333c04 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.command; +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEditException; @@ -27,6 +29,8 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.GroundFunction; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.generator.FloraGenerator; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; @@ -34,6 +38,7 @@ import com.sk89q.worldedit.function.mask.NoiseFilter2D; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.LayerVisitor; +import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.expression.ExpressionException; @@ -76,6 +81,31 @@ public class RegionCommands { public RegionCommands() { } + @Command( + name = "/set", + desc = "Sets all the blocks in the region" + ) + @CommandPermissions("worldedit.region.set") + @Logging(REGION) + public int set(Player player, EditSession editSession, + @Selection Region region, + @Arg(desc = "The patter of blocks to set") + Pattern pattern) { + RegionFunction set = new BlockReplace(editSession, pattern); + RegionVisitor visitor = new RegionVisitor(region, set); + + Operations.completeBlindly(visitor); + List messages = Lists.newArrayList(); + visitor.addStatusMessages(messages); + if (messages.isEmpty()) { + player.print("Operation completed."); + } else { + player.print("Operation completed (" + Joiner.on(", ").join(messages) + ")."); + } + + return visitor.getAffected(); + } + @Command( name = "/line", desc = "Draws a line segment between cuboid selection corners", diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java index ead39bce3..eb8b4adbc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java @@ -377,7 +377,6 @@ public final class PlatformCommandMananger { dispatcher = new CommandGraph() .builder(builder) .commands() - .register(adapt(new SelectionCommand(new ApplyCommand(new ReplaceParser(), "Set all blocks within selection"), "worldedit.region.set")), "/set") .group("brush", "br") .describeAs("Brushing commands") .register(adapt(new ShapedBrushCommand(new DeformCommand(), "worldedit.brush.deform")), "deform") From efc4ebe3096601b184f9ae406aed9f915ef0bc85 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 16 Apr 2019 23:36:03 -0700 Subject: [PATCH 059/366] Fix 1.13 entity direction code, port old schematics --- .../clipboard/io/MCEditSchematicReader.java | 22 +++++++--- .../EntityNBTCompatibilityHandler.java | 32 +++++++++++++++ .../Pre13HangingCompatibilityHandler.java | 25 ++++++++++++ .../internal/helper/MCDirections.java | 40 ++++++++++++++++++- 4 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java 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 3997f28c7..6ae3d6780 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 @@ -19,6 +19,7 @@ package com.sk89q.worldedit.extent.clipboard.io; +import com.google.common.collect.ImmutableList; import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntTag; @@ -32,7 +33,9 @@ import com.sk89q.worldedit.WorldEditException; 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.EntityNBTCompatibilityHandler; import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler; +import com.sk89q.worldedit.extent.clipboard.io.legacycompat.Pre13HangingCompatibilityHandler; import com.sk89q.worldedit.extent.clipboard.io.legacycompat.SignCompatibilityHandler; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; @@ -47,7 +50,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -59,12 +61,15 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class MCEditSchematicReader extends NBTSchematicReader { - private static final List COMPATIBILITY_HANDLERS = new ArrayList<>(); - - static { - COMPATIBILITY_HANDLERS.add(new SignCompatibilityHandler()); + private static final ImmutableList COMPATIBILITY_HANDLERS + = ImmutableList.of( + new SignCompatibilityHandler() // TODO Add a handler for skulls, flower pots, note blocks, etc. - } + ); + private static final ImmutableList ENTITY_COMPATIBILITY_HANDLERS + = ImmutableList.of( + new Pre13HangingCompatibilityHandler() + ); private static final Logger log = LoggerFactory.getLogger(MCEditSchematicReader.class); private final NBTInputStream inputStream; @@ -264,6 +269,11 @@ public class MCEditSchematicReader extends NBTSchematicReader { if (!id.isEmpty()) { EntityType entityType = EntityTypes.get(id.toLowerCase()); if (entityType != null) { + for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) { + if (compatibilityHandler.isAffectedEntity(entityType, compound)) { + compound = compatibilityHandler.updateNBT(entityType, compound); + } + } BaseEntity state = new BaseEntity(entityType, compound); clipboard.createEntity(location, state); } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java new file mode 100644 index 000000000..ffba0b566 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java @@ -0,0 +1,32 @@ +/* + * 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.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.entity.EntityType; + +import java.util.Map; + +public interface EntityNBTCompatibilityHandler { + boolean isAffectedEntity(EntityType type, CompoundTag entityTag); + CompoundTag updateNBT(EntityType type, CompoundTag entityTag); +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java new file mode 100644 index 000000000..85a181c83 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java @@ -0,0 +1,25 @@ +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.internal.helper.MCDirections; +import com.sk89q.worldedit.world.entity.EntityType; + +public class Pre13HangingCompatibilityHandler implements EntityNBTCompatibilityHandler { + + @Override + public boolean isAffectedEntity(EntityType type, CompoundTag entityTag) { + return entityTag.getValue().get("Facing") instanceof ByteTag; + } + + @Override + public CompoundTag updateNBT(EntityType type, CompoundTag entityTag) { + int newFacing = MCDirections.toHanging( + MCDirections.fromPre13Hanging(entityTag.getByte("Facing")) + ); + return entityTag.createBuilder() + .putByte("Facing", (byte) newFacing) + .build(); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java index 16e25e354..3e5d3cc3e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java @@ -30,6 +30,44 @@ public final class MCDirections { } public static Direction fromHanging(int i) { + switch (i) { + case 0: + return Direction.DOWN; + case 1: + return Direction.UP; + case 2: + return Direction.NORTH; + case 3: + return Direction.SOUTH; + case 4: + return Direction.WEST; + case 5: + return Direction.EAST; + default: + return Direction.DOWN; + } + } + + public static int toHanging(Direction direction) { + switch (direction) { + case DOWN: + return 0; + case UP: + return 1; + case NORTH: + return 2; + case SOUTH: + return 3; + case WEST: + return 4; + case EAST: + return 5; + default: + return 0; + } + } + + public static Direction fromPre13Hanging(int i) { switch (i) { case 0: return Direction.SOUTH; @@ -44,7 +82,7 @@ public final class MCDirections { } } - public static int toHanging(Direction direction) { + public static int toPre13Hanging(Direction direction) { switch (direction) { case SOUTH: return 0; From 56ef7864153e998a865995b4147d1181833bfa03 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 16 Apr 2019 23:47:29 -0700 Subject: [PATCH 060/366] Don't touch the Direction tag, as possibly only Facing changed. --- .../Pre13HangingCompatibilityHandler.java | 34 ++++++++++++++----- .../function/entity/ExtentEntityCopy.java | 17 +++++----- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java index 85a181c83..845d3beb2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java @@ -2,24 +2,40 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.CompoundTagBuilder; import com.sk89q.worldedit.internal.helper.MCDirections; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.entity.EntityType; public class Pre13HangingCompatibilityHandler implements EntityNBTCompatibilityHandler { @Override - public boolean isAffectedEntity(EntityType type, CompoundTag entityTag) { - return entityTag.getValue().get("Facing") instanceof ByteTag; + public boolean isAffectedEntity(EntityType type, CompoundTag tag) { + boolean hasLegacyDirection = tag.containsKey("Dir"); + boolean hasFacing = tag.containsKey("Facing"); + return hasLegacyDirection || hasFacing; } @Override - public CompoundTag updateNBT(EntityType type, CompoundTag entityTag) { - int newFacing = MCDirections.toHanging( - MCDirections.fromPre13Hanging(entityTag.getByte("Facing")) - ); - return entityTag.createBuilder() - .putByte("Facing", (byte) newFacing) - .build(); + public CompoundTag updateNBT(EntityType type, CompoundTag tag) { + boolean hasLegacyDirection = tag.containsKey("Dir"); + boolean hasFacing = tag.containsKey("Facing"); + int d; + if (hasLegacyDirection) { + d = MCDirections.fromLegacyHanging((byte) tag.asInt("Dir")); + } else { + d = tag.asInt("Facing"); + } + + Direction newDirection = MCDirections.fromPre13Hanging(d); + + byte hangingByte = (byte) MCDirections.toHanging(newDirection); + + CompoundTagBuilder builder = tag.createBuilder(); + builder.putByte("Direction", hangingByte); + builder.putByte("Facing", hangingByte); + builder.putByte("Dir", MCDirections.toLegacyHanging(MCDirections.toHanging(newDirection))); + return builder.build(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java index 7205c1212..1521655f6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java @@ -144,25 +144,24 @@ public class ExtentEntityCopy implements EntityFunction { .putInt("TileZ", newTilePosition.getBlockZ()); if (hasDirection || hasLegacyDirection || hasFacing) { - int d; + Direction direction; if (hasDirection) { - d = tag.asInt("Direction"); + direction = MCDirections.fromPre13Hanging(tag.asInt("Direction")); } else if (hasLegacyDirection) { - d = MCDirections.fromLegacyHanging((byte) tag.asInt("Dir")); + direction = MCDirections.fromPre13Hanging( + MCDirections.fromLegacyHanging((byte) tag.asInt("Dir")) + ); } else { - d = tag.asInt("Facing"); + direction = MCDirections.fromHanging(tag.asInt("Facing")); } - Direction direction = MCDirections.fromHanging(d); - if (direction != null) { Vector3 vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector3.ZERO)).normalize(); Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL); if (newDirection != null) { - byte hangingByte = (byte) MCDirections.toHanging(newDirection); - builder.putByte("Direction", hangingByte); - builder.putByte("Facing", hangingByte); + builder.putByte("Direction", (byte) MCDirections.toPre13Hanging(newDirection)); + builder.putByte("Facing", (byte) MCDirections.toHanging(newDirection)); builder.putByte("Dir", MCDirections.toLegacyHanging(MCDirections.toHanging(newDirection))); } } From bfc1fd8fd07eb702ca75ef29f45f6de5674d804b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 16 Apr 2019 23:50:53 -0700 Subject: [PATCH 061/366] Add licenses --- .../Pre13HangingCompatibilityHandler.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java index 845d3beb2..782ee2817 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java @@ -1,3 +1,22 @@ +/* + * 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.extent.clipboard.io.legacycompat; import com.sk89q.jnbt.ByteTag; From 526b3366b5a600a18568db2b2e56b1486a92908e Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 20 Apr 2019 12:13:58 -0400 Subject: [PATCH 062/366] Add more schematic compat, cleanup. --- .../clipboard/io/MCEditSchematicReader.java | 167 ++++++++++-------- .../FlowerPotCompatibilityHandler.java | 74 ++++++++ .../legacycompat/NBTCompatibilityHandler.java | 2 +- .../NoteBlockCompatibilityHandler.java | 43 +++++ .../Pre13HangingCompatibilityHandler.java | 28 +-- .../SignCompatibilityHandler.java | 3 +- .../function/entity/ExtentEntityCopy.java | 17 +- .../internal/helper/MCDirections.java | 24 --- 8 files changed, 230 insertions(+), 128 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java 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 6ae3d6780..4d05219d4 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 @@ -34,7 +34,9 @@ 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.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.math.BlockVector3; @@ -63,8 +65,10 @@ public class MCEditSchematicReader extends NBTSchematicReader { private static final ImmutableList COMPATIBILITY_HANDLERS = ImmutableList.of( - new SignCompatibilityHandler() - // TODO Add a handler for skulls, flower pots, note blocks, etc. + new SignCompatibilityHandler(), + new FlowerPotCompatibilityHandler(), + new NoteBlockCompatibilityHandler() + // TODO - skulls, item tags for inventories...? DFUs :> ); private static final ImmutableList ENTITY_COMPATIBILITY_HANDLERS = ImmutableList.of( @@ -167,65 +171,54 @@ public class MCEditSchematicReader extends NBTSchematicReader { // Need to pull out tile entities List tileEntities = requireTag(schematic, "TileEntities", ListTag.class).getValue(); Map> tileEntitiesMap = new HashMap<>(); + Map blockOverrides = new HashMap<>(); for (Tag tag : tileEntities) { if (!(tag instanceof CompoundTag)) continue; CompoundTag t = (CompoundTag) tag; - int x = 0; - int y = 0; - int z = 0; + int x = t.getInt("x"); + int y = t.getInt("y"); + int z = t.getInt("z"); + String id = t.getString("id"); - Map values = new HashMap<>(); - - for (Map.Entry entry : t.getValue().entrySet()) { - switch (entry.getKey()) { - case "x": - if (entry.getValue() instanceof IntTag) { - x = ((IntTag) entry.getValue()).getValue(); - } - break; - case "y": - if (entry.getValue() instanceof IntTag) { - y = ((IntTag) entry.getValue()).getValue(); - } - break; - case "z": - if (entry.getValue() instanceof IntTag) { - z = ((IntTag) entry.getValue()).getValue(); - } - break; - } - - values.put(entry.getKey(), entry.getValue()); - } + Map values = new HashMap<>(t.getValue()); + values.put("id", new StringTag(convertBlockEntityId(id))); int index = y * width * length + z * width + x; BlockState block = LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]); - if (block != null) { + BlockState newBlock = block; + if (newBlock != null) { for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { - if (handler.isAffectedBlock(block)) { - handler.updateNBT(block, values); + if (handler.isAffectedBlock(newBlock)) { + newBlock = handler.updateNBT(block, values); + if (newBlock == null) { + break; + } } } } BlockVector3 vec = BlockVector3.at(x, y, z); tileEntitiesMap.put(vec, values); + if (newBlock != block) { + blockOverrides.put(vec, newBlock); + } } BlockArrayClipboard clipboard = new BlockArrayClipboard(region); clipboard.setOrigin(origin); - // Don't log a torrent of errors - int failedBlockSets = 0; for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { for (int z = 0; z < length; ++z) { int index = y * width * length + z * width + x; BlockVector3 pt = BlockVector3.at(x, y, z); - BlockState state = LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]); + boolean useOverride = blockOverrides.containsKey(pt); + BlockState state = useOverride + ? blockOverrides.get(pt) + : LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]); try { if (state != null) { @@ -235,20 +228,11 @@ public class MCEditSchematicReader extends NBTSchematicReader { clipboard.setBlock(region.getMinimumPoint().add(pt), state); } } else { - log.warn("Unknown block when pasting schematic: " + blocks[index] + ":" + blockData[index] + ". Please report this issue."); + if (!useOverride) { + log.warn("Unknown block when pasting schematic: " + blocks[index] + ":" + blockData[index] + ". Please report this issue."); + } } - } catch (WorldEditException e) { - switch (failedBlockSets) { - case 0: - log.warn("Failed to set block on a Clipboard", e); - break; - case 1: - log.warn("Failed to set block on a Clipboard (again) -- no more messages will be logged", e); - break; - default: - } - - failedBlockSets++; + } catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this } } } @@ -258,8 +242,9 @@ public class MCEditSchematicReader extends NBTSchematicReader { // Entities // ==================================================================== - List entityTags = getTag(schematic, "Entities", ListTag.class).getValue(); - if (entityTags != null) { + ListTag entityList = getTag(schematic, "Entities", ListTag.class); + if (entityList != null) { + List entityTags = entityList.getValue(); for (Tag tag : entityTags) { if (tag instanceof CompoundTag) { CompoundTag compound = (CompoundTag) tag; @@ -289,32 +274,66 @@ public class MCEditSchematicReader extends NBTSchematicReader { private String convertEntityId(String id) { switch(id) { - case "xp_orb": - return "experience_orb"; - case "xp_bottle": - return "experience_bottle"; - case "eye_of_ender_signal": - return "eye_of_ender"; - case "ender_crystal": - return "end_crystal"; - case "fireworks_rocket": - return "firework_rocket"; - case "commandblock_minecart": - return "command_block_minecart"; - case "snowman": - return "snow_golem"; - case "villager_golem": - return "iron_golem"; - case "evocation_fangs": - return "evoker_fangs"; - case "evocation_illager": - return "evoker"; - case "vindication_illager": - return "vindicator"; - case "illusion_illager": - return "illusioner"; + case "AreaEffectCloud": return "area_effect_cloud"; + case "ArmorStand": return "armor_stand"; + case "CaveSpider": return "cave_spider"; + case "MinecartChest": return "chest_minecart"; + case "MinecartCommandBlock": return "commandblock_minecart"; + case "DragonFireball": return "dragon_fireball"; + case "ThrownEgg": return "egg"; + case "EnderCrystal": return "ender_crystal"; + case "EnderDragon": return "ender_dragon"; + case "ThrownEnderpearl": return "ender_pearl"; + case "EyeOfEnderSignal": return "eye_of_ender_signal"; + case "FallingSand": return "falling_block"; + case "FireworksRocketEntity": return "fireworks_rocket"; + case "MinecartFurnace": return "furnace_minecart"; + case "MinecartHopper": return "hopper_minecart"; + case "EntityHorse": return "horse"; + case "ItemFrame": return "item_frame"; + case "LeashKnot": return "leash_knot"; + case "LightningBolt": return "lightning_bolt"; + case "LavaSlime": return "magma_cube"; + case "MinecartRideable": return "minecart"; + case "MushroomCow": return "mooshroom"; + case "Ozelot": return "ocelot"; + case "PolarBear": return "polar_bear"; + case "ThrownPotion": return "potion"; + case "ShulkerBullet": return "shulker_bullet"; + case "SmallFireball": return "small_fireball"; + case "MinecartSpawner": return "spawner_minecart"; + case "SpectralArrow": return "spectral_arrow"; + case "PrimedTnt": return "tnt"; + case "MinecartTNT": return "tnt_minecart"; + case "VillagerGolem": return "villager_golem"; + case "WitherBoss": return "wither"; + case "WitherSkull": return "wither_skull"; + case "ThrownExpBottle": return "xp_bottle"; + case "XPOrb": return "xp_orb"; + case "PigZombie": return "zombie_pigman"; + default: return id; + } + } + + private String convertBlockEntityId(String id) { + switch(id) { + case "Cauldron": return "brewing_stand"; + case "Control": return "command_block"; + case "DLDetector": return "daylight_detector"; + case "Trap": return "dispenser"; + case "EnchantTable": return "enchanting_table"; + case "EndGateway": return "end_gateway"; + case "AirPortal": return "end_portal"; + case "EnderChest": return "ender_chest"; + case "FlowerPot": return "flower_pot"; + case "RecordPlayer": return "jukebox"; + case "MobSpawner": return "mob_spawner"; + case "Music": + case "noteblock": + return "note_block"; + case "Structure": return "structure_block"; + default: return id; } - return id; } @Override 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 new file mode 100644 index 000000000..e34573f11 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/FlowerPotCompatibilityHandler.java @@ -0,0 +1,74 @@ +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.registry.LegacyMapper; + +import java.util.Map; + +public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { + @Override + public > boolean isAffectedBlock(B block) { + return block.getBlockType() == BlockTypes.FLOWER_POT; + } + + @Override + public > B updateNBT(B block, Map values) { + Tag item = values.get("Item"); + if (item instanceof StringTag) { + String id = ((StringTag) item).getValue(); + int data = 0; + Tag dataTag = values.get("Data"); + if (dataTag instanceof IntTag) { + data = ((IntTag) dataTag).getValue(); + } + BlockState newState = convertLegacyBlockType(id, data); + if (newState != null) { + return (B) newState; // generics pls :\ + } + } + return block; + } + + private BlockState convertLegacyBlockType(String id, int data) { + int newId = 0; + switch (id) { + case "minecraft:red_flower": + newId = 38; // now poppy + break; + case "minecraft:yellow_flower": + newId = 37; // now dandelion + break; + case "minecraft:sapling": + newId = 6; // oak_sapling + break; + case "minecraft:deadbush": + case "minecraft:tallgrass": + newId = 31; // dead_bush with fern and grass (not 32!) + break; + default: + break; + } + String plantedName = null; + if (newId == 0) { + plantedName = id.substring(10); + } else { + BlockState plantedWithData = LegacyMapper.getInstance().getBlockFromLegacy(newId, data); + if (plantedWithData != null) { + plantedName = plantedWithData.getBlockType().getId().substring(10); // remove "minecraft:" + } + } + if (plantedName != null) { + BlockType potAndPlanted = BlockTypes.get("minecraft:potted_" + plantedName); + if (potAndPlanted != null) { + return potAndPlanted.getDefaultState(); + } + } + return null; + } +} 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 88c344566..0f631f561 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,5 @@ import java.util.Map; public interface NBTCompatibilityHandler { > boolean isAffectedBlock(B block); - > void updateNBT(B block, Map values); + > B 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 new file mode 100644 index 000000000..2ba296247 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/NoteBlockCompatibilityHandler.java @@ -0,0 +1,43 @@ +package com.sk89q.worldedit.extent.clipboard.io.legacycompat; + +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.registry.state.IntegerProperty; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Map; + +public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { + private static final IntegerProperty NoteProperty; + + static { + IntegerProperty temp; + try { + temp = (IntegerProperty) (Property) BlockTypes.NOTE_BLOCK.getProperty("note"); + } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { + temp = null; + } + NoteProperty = temp; + } + + @Override + public > boolean isAffectedBlock(B block) { + return NoteProperty != null && block.getBlockType() == BlockTypes.NOTE_BLOCK; + } + + @Override + public > B updateNBT(B block, Map values) { + // note that instrument was note 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"); + if (noteTag instanceof ByteTag) { + Byte note = ((ByteTag) noteTag).getValue(); + if (note != null) { + return (B) block.with(NoteProperty, (int) note); + } + } + return block; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java index 782ee2817..62f40d79c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java @@ -30,30 +30,32 @@ public class Pre13HangingCompatibilityHandler implements EntityNBTCompatibilityH @Override public boolean isAffectedEntity(EntityType type, CompoundTag tag) { - boolean hasLegacyDirection = tag.containsKey("Dir"); + if (!type.getId().startsWith("minecraft:")) { + return false; + } + boolean hasLegacyDirection = tag.containsKey("Dir") || tag.containsKey("Direction"); boolean hasFacing = tag.containsKey("Facing"); return hasLegacyDirection || hasFacing; } @Override public CompoundTag updateNBT(EntityType type, CompoundTag tag) { - boolean hasLegacyDirection = tag.containsKey("Dir"); - boolean hasFacing = tag.containsKey("Facing"); - int d; - if (hasLegacyDirection) { - d = MCDirections.fromLegacyHanging((byte) tag.asInt("Dir")); + boolean hasLegacyDir = tag.containsKey("Dir"); + boolean hasLegacyDirection = tag.containsKey("Direction"); + boolean hasPre113Facing = tag.containsKey("Facing"); + Direction newDirection; + if (hasLegacyDir) { + newDirection = MCDirections.fromPre13Hanging(MCDirections.fromLegacyHanging((byte) tag.asInt("Dir"))); + } else if (hasLegacyDirection) { + newDirection = MCDirections.fromPre13Hanging(tag.asInt("Direction")); + } else if (hasPre113Facing) { + newDirection = MCDirections.fromPre13Hanging(tag.asInt("Facing")); } else { - d = tag.asInt("Facing"); + return tag; } - - Direction newDirection = MCDirections.fromPre13Hanging(d); - byte hangingByte = (byte) MCDirections.toHanging(newDirection); - CompoundTagBuilder builder = tag.createBuilder(); - builder.putByte("Direction", hangingByte); builder.putByte("Facing", hangingByte); - builder.putByte("Dir", MCDirections.toLegacyHanging(MCDirections.toHanging(newDirection))); return builder.build(); } 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 ad75ed911..ff1ebd53f 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 @@ -39,7 +39,7 @@ public class SignCompatibilityHandler implements NBTCompatibilityHandler { } @Override - public > void updateNBT(B block, Map values) { + public > B updateNBT(B block, Map values) { for (int i = 0; i < 4; ++i) { String key = "Text" + (i + 1); Tag value = values.get(key); @@ -69,5 +69,6 @@ public class SignCompatibilityHandler implements NBTCompatibilityHandler { values.put("Text" + (i + 1), new StringTag(jsonTextObject.toString())); } } + return block; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java index 1521655f6..3c882a18a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java @@ -130,8 +130,6 @@ public class ExtentEntityCopy implements EntityFunction { if (tag != null) { // Handle hanging entities (paintings, item frames, etc.) boolean hasTilePosition = tag.containsKey("TileX") && tag.containsKey("TileY") && tag.containsKey("TileZ"); - boolean hasDirection = tag.containsKey("Direction"); - boolean hasLegacyDirection = tag.containsKey("Dir"); boolean hasFacing = tag.containsKey("Facing"); if (hasTilePosition) { @@ -143,26 +141,15 @@ public class ExtentEntityCopy implements EntityFunction { .putInt("TileY", newTilePosition.getBlockY()) .putInt("TileZ", newTilePosition.getBlockZ()); - if (hasDirection || hasLegacyDirection || hasFacing) { - Direction direction; - if (hasDirection) { - direction = MCDirections.fromPre13Hanging(tag.asInt("Direction")); - } else if (hasLegacyDirection) { - direction = MCDirections.fromPre13Hanging( - MCDirections.fromLegacyHanging((byte) tag.asInt("Dir")) - ); - } else { - direction = MCDirections.fromHanging(tag.asInt("Facing")); - } + if (hasFacing) { + Direction direction = MCDirections.fromHanging(tag.asInt("Facing")); if (direction != null) { Vector3 vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector3.ZERO)).normalize(); Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL); if (newDirection != null) { - builder.putByte("Direction", (byte) MCDirections.toPre13Hanging(newDirection)); builder.putByte("Facing", (byte) MCDirections.toHanging(newDirection)); - builder.putByte("Dir", MCDirections.toLegacyHanging(MCDirections.toHanging(newDirection))); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java index 3e5d3cc3e..959e30ae4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java @@ -82,21 +82,6 @@ public final class MCDirections { } } - public static int toPre13Hanging(Direction direction) { - switch (direction) { - case SOUTH: - return 0; - case WEST: - return 1; - case NORTH: - return 2; - case EAST: - return 3; - default: - return 0; - } - } - public static int fromLegacyHanging(byte i) { switch (i) { case 0: return 2; @@ -106,15 +91,6 @@ public final class MCDirections { } } - public static byte toLegacyHanging(int i) { - switch (i) { - case 0: return (byte) 2; - case 1: return (byte) 1; - case 2: return (byte) 0; - default: return (byte) 3; - } - } - public static Direction fromRotation(int i) { switch (i) { case 0: From fcb42f05cf142a682991873b75f5869a4f1deb9e Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 25 Apr 2019 11:13:04 -0400 Subject: [PATCH 063/366] Add skull handler. --- .../clipboard/io/MCEditSchematicReader.java | 6 +- .../NoteBlockCompatibilityHandler.java | 4 +- .../SkullBlockCompatibilityHandler.java | 81 +++++++++++++++++++ 3 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java 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 4d05219d4..dad694e66 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 @@ -39,6 +39,7 @@ import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHand 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.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; @@ -67,8 +68,9 @@ public class MCEditSchematicReader extends NBTSchematicReader { = ImmutableList.of( new SignCompatibilityHandler(), new FlowerPotCompatibilityHandler(), - new NoteBlockCompatibilityHandler() - // TODO - skulls, item tags for inventories...? DFUs :> + new NoteBlockCompatibilityHandler(), + new SkullBlockCompatibilityHandler() + // TODO - item tags for inventories...? DFUs :> ); private static final ImmutableList ENTITY_COMPATIBILITY_HANDLERS = ImmutableList.of( 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 2ba296247..9b21c75f4 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 @@ -29,13 +29,13 @@ public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { @Override public > B updateNBT(B block, Map values) { - // note that instrument was note stored (in state or nbt) previously. + // 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"); if (noteTag instanceof ByteTag) { Byte note = ((ByteTag) noteTag).getValue(); if (note != null) { - return (B) block.with(NoteProperty, (int) note); + return block.with(NoteProperty, (int) note); } } return block; 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 new file mode 100644 index 000000000..b446ac7b8 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/SkullBlockCompatibilityHandler.java @@ -0,0 +1,81 @@ +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.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Map; + +public class SkullBlockCompatibilityHandler implements NBTCompatibilityHandler { + + private static final DirectionalProperty FacingProperty; + + static { + DirectionalProperty tempFacing; + try { + tempFacing = (DirectionalProperty) (Property) BlockTypes.SKELETON_WALL_SKULL.getProperty("facing"); + } catch (NullPointerException | IllegalArgumentException | ClassCastException e) { + tempFacing = null; + } + FacingProperty = tempFacing; + } + + @Override + public > boolean isAffectedBlock(B block) { + return block.getBlockType() == BlockTypes.SKELETON_SKULL + || block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL; + } + + @Override + public > B updateNBT(B block, Map values) { + boolean isWall = block.getBlockType() == BlockTypes.SKELETON_WALL_SKULL; + Tag typeTag = values.get("SkullType"); + if (typeTag instanceof ByteTag) { + String skullType = convertSkullType(((ByteTag) typeTag).getValue(), isWall); + if (skullType != null) { + BlockType type = BlockTypes.get("minecraft:" + skullType); + if (type != null) { + BlockState state = type.getDefaultState(); + if (isWall) { + 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"); + state = state.with(newProp, (int) ((ByteTag) rotTag).getValue()); + } + } + values.remove("SkullType"); + values.remove("Rot"); + return (B) state; + } + } + } + return block; + } + + private String convertSkullType(Byte oldType, boolean isWall) { + switch (oldType) { + case 0: + return isWall ? "skeleton_wall_skull" : "skeleton_skull"; + case 1: + return isWall ? "wither_skeleton_wall_skull" : "wither_skeleton_skull"; + case 2: + return isWall ? "zombie_wall_head" : "zombie_head"; + case 3: + return isWall ? "player_wall_head" : "player_head"; + case 4: + return isWall ? "creeper_wall_head" : "creeper_head"; + case 5: + return isWall ? "dragon_wall_head" : "dragon_head"; + default: + return null; + } + } +} From 26511bcc259c3c627ba5ae111b7f512ab7ef86d5 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 25 Apr 2019 11:22:39 -0400 Subject: [PATCH 064/366] Add licenses. --- .../FlowerPotCompatibilityHandler.java | 19 +++++++++++++++++++ .../NoteBlockCompatibilityHandler.java | 19 +++++++++++++++++++ .../SkullBlockCompatibilityHandler.java | 19 +++++++++++++++++++ 3 files changed, 57 insertions(+) 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 e34573f11..225a9555e 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 @@ -1,3 +1,22 @@ +/* + * 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.extent.clipboard.io.legacycompat; import com.sk89q.jnbt.IntTag; 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 9b21c75f4..940086b8f 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 @@ -1,3 +1,22 @@ +/* + * 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.extent.clipboard.io.legacycompat; import com.sk89q.jnbt.ByteTag; 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 b446ac7b8..f4fe1a3ce 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 @@ -1,3 +1,22 @@ +/* + * 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.extent.clipboard.io.legacycompat; import com.sk89q.jnbt.ByteTag; From af1af43ac177da0398fdef5a561a307ba12ca1b6 Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 3 Apr 2019 20:57:51 -0400 Subject: [PATCH 065/366] Allow copy/pasting biomes. Copy takes a -b flag to copy biomes. Paste takes a -b flag to paste biomes (if available). This allows flexibility to create/load schematics with/without biomes (when schematic biome support is added). Also added a -m mask flag to paste to set a source mask, and a -e flag to skip pasting entities if they are loaded. --- .../worldedit/command/ClipboardCommands.java | 28 +++++-- .../command/FlattenedClipboardTransform.java | 3 + .../extent/clipboard/BlockArrayClipboard.java | 5 ++ .../worldedit/extent/clipboard/Clipboard.java | 12 +++ .../function/biome/ExtentBiomeCopy.java | 73 +++++++++++++++++++ .../function/operation/ForwardExtentCopy.java | 54 +++++++++++++- .../sk89q/worldedit/session/PasteBuilder.java | 50 ++++++++++++- 7 files changed, 214 insertions(+), 11 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java 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 0f61f0d2a..52cb67be3 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 @@ -48,6 +48,7 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.session.PasteBuilder; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; @@ -75,19 +76,21 @@ public class ClipboardCommands { help = "Copy the selection to the clipboard\n" + "Flags:\n" + " -e will also copy entities\n" + - " -m sets a source mask so that excluded blocks become air", + " -m sets a source mask so that excluded blocks become air\n" + + " -b will also copy biomes", min = 0, max = 0 ) @CommandPermissions("worldedit.clipboard.copy") public void copy(Player player, LocalSession session, EditSession editSession, @Selection Region region, @Switch('e') boolean copyEntities, - @Switch('m') Mask mask) throws WorldEditException { + @Switch('m') Mask mask, @Switch('b') boolean copyBiomes) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); clipboard.setOrigin(session.getPlacementPosition(player)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setCopyingEntities(copyEntities); + copy.setCopyingBiomes(copyBiomes); if (mask != null) { copy.setSourceMask(mask); } @@ -121,6 +124,8 @@ public class ClipboardCommands { copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); copy.setCopyingEntities(copyEntities); copy.setRemovingEntities(true); + // doesn't really make sense to "cut" biomes? so copy anyway and let them choose when pasting + copy.setCopyingBiomes(true); if (mask != null) { copy.setSourceMask(mask); } @@ -133,14 +138,17 @@ public class ClipboardCommands { @Command( aliases = { "/paste" }, usage = "", - flags = "sao", + flags = "saobem:", desc = "Paste the clipboard's contents", help = "Pastes the clipboard's contents.\n" + "Flags:\n" + " -a skips air blocks\n" + + " -b pastes biomes if available\n" + + " -e skips entities (default is don't skip!)\n" + + " -m [] skips matching blocks in the clipboard\n" + " -o pastes at the original position\n" + - " -s selects the region after pasting", + " -s selects the region after pasting\n", min = 0, max = 0 ) @@ -148,18 +156,24 @@ public class ClipboardCommands { @Logging(PLACEMENT) public void paste(Player player, LocalSession session, EditSession editSession, @Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, - @Switch('s') boolean selectPasted) throws WorldEditException { + @Switch('s') boolean selectPasted, @Switch('e') boolean skipEntities, + @Switch('b') boolean pasteBiomes, @Switch('m') Mask sourceMask) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); Clipboard clipboard = holder.getClipboard(); Region region = clipboard.getRegion(); BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player); - Operation operation = holder + PasteBuilder builder = holder .createPaste(editSession) .to(to) .ignoreAirBlocks(ignoreAirBlocks) - .build(); + .copyBiomes(pasteBiomes) + .copyEntities(!skipEntities); + if (sourceMask != null) { + builder.maskSource(sourceMask); + } + Operation operation = builder.build(); Operations.completeLegacy(operation); if (selectPasted) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java index 204f062ec..464e1ad97 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/FlattenedClipboardTransform.java @@ -115,6 +115,9 @@ class FlattenedClipboardTransform { BlockTransformExtent extent = new BlockTransformExtent(original, transform); ForwardExtentCopy copy = new ForwardExtentCopy(extent, original.getRegion(), original.getOrigin(), target, original.getOrigin()); copy.setTransform(transform); + if (original.hasBiomes()) { + copy.setCopyingBiomes(true); + } return copy; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index 9d13ea579..e3cea6c89 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -161,6 +161,11 @@ public class BlockArrayClipboard implements Clipboard { } } + @Override + public boolean hasBiomes() { + return biomes != null; + } + @Override public BiomeType getBiome(BlockVector2 position) { if (biomes != null diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java index e0022d480..aeaf07e85 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extent.clipboard; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; @@ -58,4 +59,15 @@ public interface Clipboard extends Extent { */ void setOrigin(BlockVector3 origin); + /** + * Returns true if the clipboard has biome data. This can be checked since {@link Extent#getBiome(BlockVector2)} + * strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes.OCEAN} instead of {@code null} + * if biomes aren't present. However, it might not be desired to set areas to ocean if the clipboard is defaulting + * to ocean, instead of having biomes explicitly set. + * + * @return true if the clipboard has biome data set + */ + default boolean hasBiomes() { + return false; + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java new file mode 100644 index 000000000..43dbf984d --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java @@ -0,0 +1,73 @@ +/* + * 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.function.biome; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.FlatRegionFunction; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.world.biome.BiomeType; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Copies the biome from one extent to another. + */ +public class ExtentBiomeCopy implements FlatRegionFunction { + + private final Extent source; + private final Extent destination; + private final BlockVector2 from; + private final BlockVector2 to; + private final Transform transform; + + /** + * Make a new biome copy. + * + * @param source the source extent + * @param from the source offset + * @param destination the destination extent + * @param to the destination offset + * @param transform a transform to apply to positions (after source offset, before destination offset) + */ + public ExtentBiomeCopy(Extent source, BlockVector2 from, Extent destination, BlockVector2 to, Transform transform) { + checkNotNull(source); + checkNotNull(from); + checkNotNull(destination); + checkNotNull(to); + checkNotNull(transform); + this.source = source; + this.from = from; + this.destination = destination; + this.to = to; + this.transform = transform; + } + + @Override + public boolean apply(BlockVector2 position) throws WorldEditException { + BiomeType biome = source.getBiome(position); + BlockVector2 orig = position.subtract(from); + BlockVector2 transformed = transform.apply(orig.toVector3(0)).toVector2().toBlockPoint(); + + return destination.setBiome(transformed.add(to), biome); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java index cbf73e857..6ca5ad6a6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java @@ -28,17 +28,24 @@ import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.metadata.EntityProperties; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.CombinedRegionFunction; +import com.sk89q.worldedit.function.FlatRegionFunction; +import com.sk89q.worldedit.function.FlatRegionMaskingFilter; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.RegionMaskingFilter; +import com.sk89q.worldedit.function.biome.ExtentBiomeCopy; import com.sk89q.worldedit.function.block.ExtentBlockCopy; import com.sk89q.worldedit.function.entity.ExtentEntityCopy; import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Mask2D; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.visitor.EntityVisitor; +import com.sk89q.worldedit.function.visitor.FlatRegionVisitor; import com.sk89q.worldedit.function.visitor.RegionVisitor; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.transform.Identity; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.regions.FlatRegion; import com.sk89q.worldedit.regions.Region; import java.util.List; @@ -61,6 +68,7 @@ public class ForwardExtentCopy implements Operation { private Mask sourceMask = Masks.alwaysTrue(); private boolean removingEntities; private boolean copyingEntities = true; // default to true for backwards compatibility, sort of + private boolean copyingBiomes; private RegionFunction sourceFunction = null; private Transform transform = new Identity(); private Transform currentTransform = null; @@ -222,6 +230,27 @@ public class ForwardExtentCopy implements Operation { this.removingEntities = removingEntities; } + /** + * Return whether biomes should be copied along with blocks. + * + * @return true if copying biomes + */ + public boolean isCopyingBiomes() { + return copyingBiomes; + } + + /** + * Set whether biomes should be copies along with blocks. + * + * @param copyingBiomes true if copying + */ + public void setCopyingBiomes(boolean copyingBiomes) { + if (copyingBiomes && !(region instanceof FlatRegion)) { + throw new UnsupportedOperationException("Can't copy biomes from region that doesn't implement FlatRegion"); + } + this.copyingBiomes = copyingBiomes; + } + /** * Get the number of affected objects. * @@ -254,6 +283,25 @@ public class ForwardExtentCopy implements Operation { lastVisitor = blockVisitor; + if (!copyingBiomes && !copyingEntities) { + return new DelegateOperation(this, blockVisitor); + } + + List ops = Lists.newArrayList(blockVisitor); + + if (copyingBiomes && region instanceof FlatRegion) { // double-check here even though we checked before + ExtentBiomeCopy biomeCopy = new ExtentBiomeCopy(source, from.toBlockVector2(), + destination, to.toBlockVector2(), currentTransform); + Mask2D biomeMask = sourceMask.toMask2D(); + if (biomeMask != null) { + FlatRegionMaskingFilter filteredBiomeCopy = new FlatRegionMaskingFilter(biomeMask, biomeCopy); + FlatRegionVisitor biomeVisitor = new FlatRegionVisitor(((FlatRegion) region), filteredBiomeCopy); + ops.add(biomeVisitor); + } else { + ops.add(new FlatRegionVisitor(((FlatRegion) region), biomeCopy)); + } + } + if (copyingEntities) { ExtentEntityCopy entityCopy = new ExtentEntityCopy(from.toVector3(), destination, to.toVector3(), currentTransform); entityCopy.setRemoving(removingEntities); @@ -263,10 +311,10 @@ public class ForwardExtentCopy implements Operation { return properties != null && !properties.isPasteable(); }); EntityVisitor entityVisitor = new EntityVisitor(entities.iterator(), entityCopy); - return new DelegateOperation(this, new OperationQueue(blockVisitor, entityVisitor)); - } else { - return new DelegateOperation(this, blockVisitor); + ops.add(entityVisitor); } + + return new DelegateOperation(this, new OperationQueue(ops)); } else { return null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java index d50a277ac..c46939661 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java @@ -25,6 +25,9 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.transform.BlockTransformExtent; import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.MaskIntersection; +import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector3; @@ -39,8 +42,12 @@ public class PasteBuilder { private final Transform transform; private final Extent targetExtent; + private Mask sourceMask = Masks.alwaysTrue(); + private BlockVector3 to = BlockVector3.ZERO; private boolean ignoreAirBlocks; + private boolean copyEntities = true; // default because it used to be this way + private boolean copyBiomes; /** * Create a new instance. @@ -67,6 +74,19 @@ public class PasteBuilder { return this; } + /** + * Set a custom mask of blocks to ignore from the source. + * This provides a more flexible alternative to {@link #ignoreAirBlocks(boolean)}, for example + * one might want to ignore structure void if copying a Minecraft Structure, etc. + * + * @param sourceMask + * @return this builder instance + */ + public PasteBuilder maskSource(Mask sourceMask) { + this.sourceMask = sourceMask; + return this; + } + /** * Set whether air blocks in the source are skipped over when pasting. * @@ -77,6 +97,29 @@ public class PasteBuilder { return this; } + /** + * Set whether the copy should include source entities. + * Note that this is true by default for legacy reasons. + * + * @param copyEntities + * @return this builder instance + */ + public PasteBuilder copyEntities(boolean copyEntities) { + this.copyEntities = copyEntities; + return this; + } + + /** + * Set whether the copy should include source biomes (if available). + * + * @param copyBiomes + * @return this builder instance + */ + public PasteBuilder copyBiomes(boolean copyBiomes) { + this.copyBiomes = copyBiomes; + return this; + } + /** * Build the operation. * @@ -87,8 +130,13 @@ public class PasteBuilder { ForwardExtentCopy copy = new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(), targetExtent, to); copy.setTransform(transform); if (ignoreAirBlocks) { - copy.setSourceMask(new ExistingBlockMask(clipboard)); + copy.setSourceMask(sourceMask == Masks.alwaysTrue() ? new ExistingBlockMask(clipboard) + : new MaskIntersection(sourceMask, new ExistingBlockMask(clipboard))); + } else { + copy.setSourceMask(sourceMask); } + copy.setCopyingEntities(copyEntities); + copy.setCopyingBiomes(copyBiomes && clipboard.hasBiomes()); return copy; } From 17fba54305770303b5bbbc6539ee895fc818969e Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 3 Apr 2019 23:33:10 -0400 Subject: [PATCH 066/366] Update SpongeSchematic format to version 2. Allows saving and loading entities and biomes. --- .../bukkit/BukkitServerInterface.java | 6 + .../com/sk89q/jnbt/CompoundTagBuilder.java | 12 ++ .../extension/platform/Platform.java | 7 + .../extent/clipboard/BlockArrayClipboard.java | 5 +- .../clipboard/io/MCEditSchematicReader.java | 2 + .../clipboard/io/SpongeSchematicReader.java | 120 ++++++++++++++++- .../clipboard/io/SpongeSchematicWriter.java | 121 ++++++++++++++++-- .../world/storage/NBTConversions.java | 2 +- .../sk89q/worldedit/forge/ForgePlatform.java | 6 + .../worldedit/sponge/SpongePlatform.java | 6 + 10 files changed, 273 insertions(+), 14 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index adfc64bc0..0123b452b 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -65,6 +65,12 @@ public class BukkitServerInterface implements MultiUserPlatform { return BukkitRegistries.getInstance(); } + @Override + public int getDataVersion() { + // TODO - add to adapter - CraftMagicNumbers#getDataVersion + return 1631; + } + @Override public boolean isValidMobType(String type) { final EntityType entityType = EntityType.fromName(type); diff --git a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java index b0e873c0d..6b5776619 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/CompoundTagBuilder.java @@ -181,6 +181,18 @@ public class CompoundTagBuilder { return put(key, new StringTag(value)); } + /** + * Remove the given key from the compound tag. Does nothing if the key doesn't exist. + * + * @param key the key + * @return this object + */ + public CompoundTagBuilder remove(String key) { + checkNotNull(key); + entries.remove(key); + return this; + } + /** * Put all the entries from the given map into this map. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index 3b37a98b5..6878235d5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -45,6 +45,13 @@ public interface Platform { */ Registries getRegistries(); + /** + * Gets the Minecraft data version being used by the platform. + * + * @return the data version + */ + int getDataVersion(); + /** * Checks if a mob type is valid. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java index e3cea6c89..029d25052 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/BlockArrayClipboard.java @@ -171,7 +171,10 @@ public class BlockArrayClipboard implements Clipboard { if (biomes != null && position.containedWithin(getMinimumPoint().toBlockVector2(), getMaximumPoint().toBlockVector2())) { BlockVector2 v = position.subtract(region.getMinimumPoint().toBlockVector2()); - return biomes[v.getBlockX()][v.getBlockZ()]; + BiomeType biomeType = biomes[v.getBlockX()][v.getBlockZ()]; + if (biomeType != null) { + return biomeType; + } } return BiomeTypes.OCEAN; 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 dad694e66..a5e87c356 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 @@ -53,6 +53,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -315,6 +316,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { case "PigZombie": return "zombie_pigman"; default: return id; } + return id; } private String convertBlockEntityId(String id) { 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 09594e388..57d8582b2 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 @@ -28,18 +28,27 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NamedTag; import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; 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.BlockState; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.storage.NBTConversions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,6 +98,15 @@ public class SpongeSchematicReader extends NBTSchematicReader { int version = requireTag(schematic, "Version", IntTag.class).getValue(); if (version == 1) { return readVersion1(schematicTag); + } else if (version == 2) { + int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); + if (dataVersion > WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.WORLD_EDITING).getDataVersion()) { + // maybe should just warn? simple schematics may be compatible still. + throw new IOException("Schematic was made in a newer Minecraft version. Data may be incompatible."); + } + BlockArrayClipboard clip = readVersion1(schematicTag); + return readVersion2(clip, schematicTag); } throw new IOException("This schematic version is currently not supported"); } @@ -123,10 +141,11 @@ public class SpongeSchematicReader extends NBTSchematicReader { region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); } + // Note: these aren't actually required by the spec, but we require them I guess? int paletteMax = requireTag(schematic, "PaletteMax", IntTag.class).getValue(); Map paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); if (paletteObject.size() != paletteMax) { - throw new IOException("Differing given palette size to actual size"); + throw new IOException("Block palette size does not match expected size."); } Map palette = new HashMap<>(); @@ -168,8 +187,8 @@ public class SpongeSchematicReader extends NBTSchematicReader { int index = 0; int i = 0; - int value = 0; - int varintLength = 0; + int value; + int varintLength; while (i < blocks.length) { value = 0; varintLength = 0; @@ -185,7 +204,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { } i++; } - // index = (y * length + z) * width + x + // index = (y * length * width) + (z * width) + x int y = index / (width * length); int z = (index % (width * length)) / width; int x = (index % (width * length)) % width; @@ -219,6 +238,99 @@ public class SpongeSchematicReader extends NBTSchematicReader { return clipboard; } + private Clipboard readVersion2(BlockArrayClipboard version1, CompoundTag schematicTag) throws IOException { + Map schematic = schematicTag.getValue(); + if (schematic.containsKey("BiomeData")) { + readBiomes(version1, schematic); + } + if (schematic.containsKey("Entities")) { + readEntities(version1, schematic); + } + return version1; + } + + private void readBiomes(BlockArrayClipboard clipboard, Map schematic) throws IOException { + ByteArrayTag dataTag = requireTag(schematic, "BiomeData", ByteArrayTag.class); + // TODO for now, we just assume if biomedata is present, palette will be as well. + // atm the spec doesn't actually require palettes + IntTag maxTag = requireTag(schematic, "BiomePaletteMax", IntTag.class); + CompoundTag paletteTag = requireTag(schematic, "BiomePalette", CompoundTag.class); + + Map palette = new HashMap<>(); + if (maxTag.getValue() != paletteTag.getValue().size()) { + throw new IOException("Biome palette size does not match expected size."); + } + Map paletteEntries = paletteTag.getValue(); + + for (Map.Entry palettePart : paletteEntries.entrySet()) { + BiomeType biome = BiomeTypes.get(palettePart.getKey()); + if (biome == null) { + log.warn("Unknown biome type '" + palettePart.getKey() + "' 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)) { + throw new IOException("Biome mapped to non-Int tag."); + } + palette.put(((IntTag) idTag).getValue(), biome); + } + + int width = clipboard.getDimensions().getX(); + + byte[] biomes = dataTag.getValue(); + int biomeIndex = 0; + int biomeJ = 0; + int bVal; + int varIntLength; + while (biomeJ < biomes.length) { + bVal = 0; + varIntLength = 0; + + while (true) { + bVal |= (biomes[biomeJ] & 127) << (varIntLength++ * 7); + if (varIntLength > 5) { + throw new RuntimeException("VarInt too big (probably corrupted data)"); + } + if (((biomes[biomeJ] & 128) != 128)) { + biomeJ++; + break; + } + biomeJ++; + } + int z = biomeIndex / width; + int x = biomeIndex % width; + BiomeType type = palette.get(bVal); + clipboard.setBiome(clipboard.getMinimumPoint().toBlockVector2().add(x, z), type); + biomeIndex++; + } + } + + private void readEntities(BlockArrayClipboard clipboard, Map schematic) throws IOException { + List entList = requireTag(schematic, "Entities", ListTag.class).getValue(); + if (entList.isEmpty()) { + return; + } + for (Tag et : entList) { + if (!(et instanceof CompoundTag)) { + continue; + } + CompoundTag entityTag = (CompoundTag) et; + Map tags = entityTag.getValue(); + String id = requireTag(tags, "Id", StringTag.class).getValue(); + + EntityType entityType = EntityTypes.get(id); + if (entityType != null) { + Location location = NBTConversions.toLocation(clipboard, + requireTag(tags, "Pos", ListTag.class), + requireTag(tags, "Rotation", ListTag.class)); + BaseEntity state = new BaseEntity(entityType, + entityTag.createBuilder().putString("id", id).remove("Id").build()); + clipboard.createEntity(location, state); + } else { + log.warn("Unknown entity when pasting schematic: " + id); + } + } + } + @Override public void close() throws IOException { inputStream.close(); 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 8237106f6..f9d9248a6 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 @@ -21,8 +21,12 @@ package com.sk89q.worldedit.extent.clipboard.io; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.Lists; +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; @@ -30,9 +34,16 @@ import com.sk89q.jnbt.NBTOutputStream; import com.sk89q.jnbt.ShortTag; 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.extension.platform.Capability; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector2; 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; import com.sk89q.worldedit.world.block.BaseBlock; import java.io.ByteArrayOutputStream; @@ -41,12 +52,15 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * Writes schematic files using the Sponge schematic format. */ public class SpongeSchematicWriter implements ClipboardWriter { + private static final int CURRENT_VERSION = 2; + private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE; private final NBTOutputStream outputStream; @@ -63,17 +77,17 @@ public class SpongeSchematicWriter implements ClipboardWriter { @Override public void write(Clipboard clipboard) throws IOException { // For now always write the latest version. Maybe provide support for earlier if more appear. - outputStream.writeNamedTag("Schematic", new CompoundTag(write1(clipboard))); + outputStream.writeNamedTag("Schematic", new CompoundTag(write2(clipboard))); } /** - * Writes a version 1 schematic file. + * Writes a version 2 schematic file. * * @param clipboard The clipboard * @return The schematic map * @throws IOException If an error occurs */ - private Map write1(Clipboard clipboard) throws IOException { + private Map write2(Clipboard clipboard) throws IOException { Region region = clipboard.getRegion(); BlockVector3 origin = clipboard.getOrigin(); BlockVector3 min = region.getMinimumPoint(); @@ -93,7 +107,9 @@ public class SpongeSchematicWriter implements ClipboardWriter { } Map schematic = new HashMap<>(); - schematic.put("Version", new IntTag(1)); + schematic.put("Version", new IntTag(CURRENT_VERSION)); + schematic.put("DataVersion", new IntTag( + WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion())); Map metadata = new HashMap<>(); metadata.put("WEOffsetX", new IntTag(offset.getBlockX())); @@ -129,10 +145,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { BlockVector3 point = BlockVector3.at(x0, y0, z0); BaseBlock block = clipboard.getFullBlock(point); if (block.getNbtData() != null) { - Map values = new HashMap<>(); - for (Map.Entry entry : block.getNbtData().getValue().entrySet()) { - values.put(entry.getKey(), entry.getValue()); - } + Map values = new HashMap<>(block.getNbtData().getValue()); values.remove("id"); // Remove 'id' if it exists. We want 'Id' @@ -179,9 +192,101 @@ public class SpongeSchematicWriter implements ClipboardWriter { schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray())); schematic.put("TileEntities", new ListTag(CompoundTag.class, tileEntities)); + // version 2 stuff + if (clipboard.hasBiomes()) { + writeBiomes(clipboard, schematic); + } + + if (!clipboard.getEntities().isEmpty()) { + writeEntities(clipboard, schematic); + } + return schematic; } + private void writeBiomes(Clipboard clipboard, Map schematic) { + BlockVector3 min = clipboard.getMinimumPoint(); + int width = clipboard.getRegion().getWidth(); + int length = clipboard.getRegion().getLength(); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(width * length); + + int paletteMax = 0; + Map palette = new HashMap<>(); + + for (int z = 0; z < length; z++) { + int z0 = min.getBlockZ() + z; + for (int x = 0; x < width; x++) { + int x0 = min.getBlockX() + x; + BlockVector2 pt = BlockVector2.at(x0, z0); + BiomeType biome = clipboard.getBiome(pt); + + String biomeKey = biome.getId(); + int biomeId; + if (palette.containsKey(biomeKey)) { + biomeId = palette.get(biomeKey); + } else { + biomeId = paletteMax; + palette.put(biomeKey, biomeId); + paletteMax++; + } + + while ((biomeId & -128) != 0) { + buffer.write(biomeId & 127 | 128); + biomeId >>>= 7; + } + buffer.write(biomeId); + } + } + + schematic.put("BiomePaletteMax", new IntTag(paletteMax)); + + Map paletteTag = new HashMap<>(); + palette.forEach((key, value) -> paletteTag.put(key, new IntTag(value))); + + schematic.put("BiomePalette", new CompoundTag(paletteTag)); + schematic.put("BiomeData", new ByteArrayTag(buffer.toByteArray())); + } + + private void writeEntities(Clipboard clipboard, Map schematic) { + 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(e -> e != null).collect(Collectors.toList()); + if (entities.isEmpty()) { + return; + } + schematic.put("Entities", new ListTag(CompoundTag.class, entities)); + } + + private 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); + } + + private 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/world/storage/NBTConversions.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java index 6b61bddf9..3da5c0047 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/NBTConversions.java @@ -52,7 +52,7 @@ public final class NBTConversions { return new Location( extent, positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), - (float) directionTag.asDouble(0), (float) directionTag.asDouble(1)); + directionTag.getFloat(0), directionTag.getFloat(1)); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 0530acc54..d578c3b9f 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -64,6 +64,12 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { return ForgeRegistries.getInstance(); } + @Override + public int getDataVersion() { + // TODO technically available as WorldInfo#field_209227_p but requires a world ref? + return 1631; + } + @Override public boolean isValidMobType(String type) { return net.minecraftforge.registries.ForgeRegistries.ENTITIES.containsKey(new ResourceLocation(type)); diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java index 774347645..33a4395e0 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java @@ -68,6 +68,12 @@ class SpongePlatform extends AbstractPlatform implements MultiUserPlatform { return SpongeRegistries.getInstance(); } + @Override + public int getDataVersion() { + // TODO add to adapter - org.spongepowered.common.data.util.DataUtil#MINECRAFT_DATA_VERSION + return 1631; + } + @Override public boolean isValidMobType(String type) { return Sponge.getRegistry().getType(EntityType.class, type).isPresent(); From f0587354bec79fa4e1dcffda73735db91053297d Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 5 Apr 2019 19:40:25 -0400 Subject: [PATCH 067/366] Cleanup, make copy/paste flags consistent, add status messages. --- .../worldedit/command/ClipboardCommands.java | 35 ++++++++----- .../clipboard/io/SpongeSchematicReader.java | 16 +++--- .../function/operation/ForwardExtentCopy.java | 52 +++++++++++++++---- 3 files changed, 72 insertions(+), 31 deletions(-) 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 52cb67be3..cffdbb2ce 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 @@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT; import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION; +import com.google.common.collect.Lists; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.Logging; @@ -52,6 +53,8 @@ import com.sk89q.worldedit.session.PasteBuilder; import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.parametric.Optional; +import java.util.List; + /** * Clipboard commands. */ @@ -76,8 +79,8 @@ public class ClipboardCommands { help = "Copy the selection to the clipboard\n" + "Flags:\n" + " -e will also copy entities\n" + - " -m sets a source mask so that excluded blocks become air\n" + - " -b will also copy biomes", + " -b will also copy biomes\n" + + " -m sets a source mask so that excluded blocks become air", min = 0, max = 0 ) @@ -97,17 +100,21 @@ public class ClipboardCommands { Operations.completeLegacy(copy); session.setClipboard(new ClipboardHolder(clipboard)); - player.print(region.getArea() + " block(s) were copied."); + List messages = Lists.newArrayList(); + copy.addStatusMessages(messages); + messages.forEach(player::print); } @Command( aliases = { "/cut" }, flags = "em", - usage = "[leave-id]", + usage = "[leave-pattern]", desc = "Cut the selection to the clipboard", help = "Copy the selection to the clipboard\n" + + "The space will be filled with the leave pattern if specified, otherwise air." + "Flags:\n" + " -e will also cut entities\n" + + " -b will also copy biomes (source biomes unaffected)\n" + " -m sets a source mask so that excluded blocks become air\n" + "WARNING: Cutting and pasting entities cannot yet be undone!", max = 1 @@ -116,7 +123,7 @@ public class ClipboardCommands { @Logging(REGION) public void cut(Player player, LocalSession session, EditSession editSession, @Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities, - @Switch('m') Mask mask) throws WorldEditException { + @Switch('m') Mask mask, @Switch('b') boolean copyBiomes) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); clipboard.setOrigin(session.getPlacementPosition(player)); @@ -124,20 +131,20 @@ public class ClipboardCommands { copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); copy.setCopyingEntities(copyEntities); copy.setRemovingEntities(true); - // doesn't really make sense to "cut" biomes? so copy anyway and let them choose when pasting - copy.setCopyingBiomes(true); + copy.setCopyingBiomes(copyBiomes); if (mask != null) { copy.setSourceMask(mask); } Operations.completeLegacy(copy); session.setClipboard(new ClipboardHolder(clipboard)); - player.print(region.getArea() + " block(s) were cut."); + List messages = Lists.newArrayList(); + copy.addStatusMessages(messages); + messages.forEach(player::print); } @Command( aliases = { "/paste" }, - usage = "", flags = "saobem:", desc = "Paste the clipboard's contents", help = @@ -145,18 +152,17 @@ public class ClipboardCommands { "Flags:\n" + " -a skips air blocks\n" + " -b pastes biomes if available\n" + - " -e skips entities (default is don't skip!)\n" + + " -e pastes entities if available\n" + " -m [] skips matching blocks in the clipboard\n" + " -o pastes at the original position\n" + " -s selects the region after pasting\n", - min = 0, max = 0 ) @CommandPermissions("worldedit.clipboard.paste") @Logging(PLACEMENT) public void paste(Player player, LocalSession session, EditSession editSession, @Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin, - @Switch('s') boolean selectPasted, @Switch('e') boolean skipEntities, + @Switch('s') boolean selectPasted, @Switch('e') boolean pasteEntities, @Switch('b') boolean pasteBiomes, @Switch('m') Mask sourceMask) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); @@ -169,7 +175,7 @@ public class ClipboardCommands { .to(to) .ignoreAirBlocks(ignoreAirBlocks) .copyBiomes(pasteBiomes) - .copyEntities(!skipEntities); + .copyEntities(pasteEntities); if (sourceMask != null) { builder.maskSource(sourceMask); } @@ -187,6 +193,9 @@ public class ClipboardCommands { } player.print("The clipboard has been pasted at " + to); + List messages = Lists.newArrayList(); + operation.addStatusMessages(messages); + messages.forEach(player::print); } @Command( 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 57d8582b2..556a60570 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 @@ -39,6 +39,7 @@ import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; @@ -57,6 +58,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -141,7 +143,6 @@ public class SpongeSchematicReader extends NBTSchematicReader { region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); } - // Note: these aren't actually required by the spec, but we require them I guess? int paletteMax = requireTag(schematic, "PaletteMax", IntTag.class).getValue(); Map paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); if (paletteObject.size() != paletteMax) { @@ -161,7 +162,8 @@ public class SpongeSchematicReader extends NBTSchematicReader { try { state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState(); } catch (InputParseException e) { - throw new IOException("Invalid BlockState in schematic: " + palettePart + ". Are you missing a mod or using a schematic made in a newer version of Minecraft?"); + throw new IOException("Invalid BlockState in palette: " + palettePart + + ". Are you missing a mod or using a schematic made in a newer version of Minecraft?"); } palette.put(id, state); } @@ -251,8 +253,6 @@ public class SpongeSchematicReader extends NBTSchematicReader { private void readBiomes(BlockArrayClipboard clipboard, Map schematic) throws IOException { ByteArrayTag dataTag = requireTag(schematic, "BiomeData", ByteArrayTag.class); - // TODO for now, we just assume if biomedata is present, palette will be as well. - // atm the spec doesn't actually require palettes IntTag maxTag = requireTag(schematic, "BiomePaletteMax", IntTag.class); CompoundTag paletteTag = requireTag(schematic, "BiomePalette", CompoundTag.class); @@ -262,10 +262,11 @@ public class SpongeSchematicReader extends NBTSchematicReader { } Map paletteEntries = paletteTag.getValue(); - for (Map.Entry palettePart : paletteEntries.entrySet()) { + for (Entry palettePart : paletteEntries.entrySet()) { BiomeType biome = BiomeTypes.get(palettePart.getKey()); if (biome == null) { - log.warn("Unknown biome type '" + palettePart.getKey() + "' in palette. Are you missing a mod or using a schematic made in a newer version of Minecraft?"); + log.warn("Unknown biome type :" + palettePart.getKey() + + " 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)) { @@ -281,6 +282,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { int biomeJ = 0; int bVal; int varIntLength; + BlockVector2 min = clipboard.getMinimumPoint().toBlockVector2(); while (biomeJ < biomes.length) { bVal = 0; varIntLength = 0; @@ -299,7 +301,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { int z = biomeIndex / width; int x = biomeIndex % width; BiomeType type = palette.get(bVal); - clipboard.setBiome(clipboard.getMinimumPoint().toBlockVector2().add(x, z), type); + clipboard.setBiome(min.add(x, z), type); biomeIndex++; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java index 6ca5ad6a6..9512b5c3d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/ForwardExtentCopy.java @@ -41,7 +41,6 @@ import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.function.visitor.FlatRegionVisitor; import com.sk89q.worldedit.function.visitor.RegionVisitor; -import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.transform.Identity; import com.sk89q.worldedit.math.transform.Transform; @@ -72,8 +71,14 @@ public class ForwardExtentCopy implements Operation { private RegionFunction sourceFunction = null; private Transform transform = new Identity(); private Transform currentTransform = null; + private RegionVisitor lastVisitor; - private int affected; + private FlatRegionVisitor lastBiomeVisitor; + private EntityVisitor lastEntityVisitor; + + private int affectedBlocks; + private int affectedBiomeCols; + private int affectedEntities; /** * Create a new copy using the region's lowest minimum point as the @@ -257,15 +262,23 @@ public class ForwardExtentCopy implements Operation { * @return the number of affected */ public int getAffected() { - return affected; + return affectedBlocks + affectedBiomeCols + affectedEntities; } @Override public Operation resume(RunContext run) throws WorldEditException { if (lastVisitor != null) { - affected += lastVisitor.getAffected(); + affectedBlocks += lastVisitor.getAffected(); lastVisitor = null; } + if (lastBiomeVisitor != null) { + affectedBiomeCols += lastBiomeVisitor.getAffected(); + lastBiomeVisitor = null; + } + if (lastEntityVisitor != null) { + affectedEntities += lastEntityVisitor.getAffected(); + lastEntityVisitor = null; + } if (repetitions > 0) { repetitions--; @@ -293,13 +306,11 @@ public class ForwardExtentCopy implements Operation { ExtentBiomeCopy biomeCopy = new ExtentBiomeCopy(source, from.toBlockVector2(), destination, to.toBlockVector2(), currentTransform); Mask2D biomeMask = sourceMask.toMask2D(); - if (biomeMask != null) { - FlatRegionMaskingFilter filteredBiomeCopy = new FlatRegionMaskingFilter(biomeMask, biomeCopy); - FlatRegionVisitor biomeVisitor = new FlatRegionVisitor(((FlatRegion) region), filteredBiomeCopy); - ops.add(biomeVisitor); - } else { - ops.add(new FlatRegionVisitor(((FlatRegion) region), biomeCopy)); - } + FlatRegionFunction biomeFunction = biomeMask == null ? biomeCopy + : new FlatRegionMaskingFilter(biomeMask, biomeCopy); + FlatRegionVisitor biomeVisitor = new FlatRegionVisitor(((FlatRegion) region), biomeFunction); + ops.add(biomeVisitor); + lastBiomeVisitor = biomeVisitor; } if (copyingEntities) { @@ -312,6 +323,7 @@ public class ForwardExtentCopy implements Operation { }); EntityVisitor entityVisitor = new EntityVisitor(entities.iterator(), entityCopy); ops.add(entityVisitor); + lastEntityVisitor = entityVisitor; } return new DelegateOperation(this, new OperationQueue(ops)); @@ -326,6 +338,24 @@ public class ForwardExtentCopy implements Operation { @Override public void addStatusMessages(List messages) { + StringBuilder msg = new StringBuilder(); + msg.append(affectedBlocks).append(" block(s)"); + if (affectedBiomeCols > 0) { + if (affectedEntities > 0) { + msg.append(", "); + } else { + msg.append(" and "); + } + msg.append(affectedBiomeCols).append(" biome(s)"); + } + if (affectedEntities > 0) { + if (affectedBiomeCols > 0) { + msg.append(","); + } + msg.append(" and ").append(affectedEntities).append(" entities(s)"); + } + msg.append(" affected."); + messages.add(msg.toString()); } } From 31a8328fb57ed5497470206dcc165bfdd3f44974 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 25 Apr 2019 18:58:06 -0400 Subject: [PATCH 068/366] Add data version to BukkitImplAdapter. Also throttle unknown-block warning when loading MCEdit schematics. --- .../bukkit/BukkitServerInterface.java | 6 ++++-- .../bukkit/adapter/BukkitImplAdapter.java | 7 +++++++ .../adapter/impl/Spigot_v1_13_R1$1.class | Bin 959 -> 959 bytes .../bukkit/adapter/impl/Spigot_v1_13_R1.class | Bin 25466 -> 25603 bytes .../adapter/impl/Spigot_v1_13_R2$1.class | Bin 959 -> 959 bytes .../bukkit/adapter/impl/Spigot_v1_13_R2.class | Bin 25488 -> 25718 bytes .../adapter/impl/Spigot_v1_13_R2_2$1.class | Bin 965 -> 965 bytes .../adapter/impl/Spigot_v1_13_R2_2.class | Bin 25554 -> 25784 bytes .../adapter/impl/Spigot_v1_14_R1$1.class | Bin 959 -> 959 bytes .../bukkit/adapter/impl/Spigot_v1_14_R1.class | Bin 25746 -> 25976 bytes .../clipboard/io/MCEditSchematicReader.java | 15 ++++++++++----- 11 files changed, 21 insertions(+), 7 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 0123b452b..9dfc856b2 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -67,8 +67,10 @@ public class BukkitServerInterface implements MultiUserPlatform { @Override public int getDataVersion() { - // TODO - add to adapter - CraftMagicNumbers#getDataVersion - return 1631; + if (plugin.getBukkitImplAdapter() != null) { + return plugin.getBukkitImplAdapter().getDataVersion(); + } + return 0; } @Override 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 1a4329a4f..9ac0fe8de 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 @@ -40,6 +40,13 @@ import javax.annotation.Nullable; */ public interface BukkitImplAdapter { + /** + * Get the Minecraft data version for the current world data. + * + * @return the data version + */ + int getDataVersion(); + /** * Get the block at the given location. * diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class index efa78dacc6f7d28a602adf0b9f4189588b996348..68556cab91070ba9b83d00f939940eaabed68d22 100644 GIT binary patch delta 13 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 ItJTW?1I5wJm;e9( delta 9435 zcmZ`<2YeJo)PHYg@8+_%ffO#}fFy(@Kng`bkOPCXCx?2>u~Hx_ZItCx9_e~9sEn80B$sKU)`YN47N)k5wWLdulEENL*I zrOLKdE0tqZuH5saX)R3~Y1;Z#zACU)p(?T|N3}Dmy-kIxgRMHMQ;h0lQ+p99OLdl} zi&3ZAs;lZI&1v#ZcRQ>?sz(C#R6YIbbX9DtUg`|lNpD;AQGJc-XJf3tjFm|5OyP5u zjY$KH8fa4=b+%9j`FMm;gKa8NL$Ibg$Hy1=xKxIQ$~xytb6x^xt6?^cSHlz3`D%nT zBg4{OAWf+>qoldeuSTnj{A!FE>sRAcnKa{#n&78VYNAo)ej2SVw$&tciBKjRHN~i@ zMop9DE;VYpQ8R3ss4hz(QdijON_CZ=rl_lpnk$;R#;9v;nx?LkJzXC*DlGHnNi*N5 z8*Fu>y2+-Q>Sk$fvDK|m2*z%c$FmdE?dlFcEmUJg%sXY^E-}R2(%d7>z0%w#&HZA+ z2NG07Es&)iOd(bkwt7@OCYpTQsD(D&7Ush~^#nTVNoktH>(o;s+tYsaj2dgyvqmj4 z>N!8%r=FMQX=~nyH3Y)@7s>Y`0REFsMO`}%Yv_!2+P^(p~QEP0qR$OkaxZGN}9KEdG zvenz_9i!ISRH@b*^{!2Cz{jAC_oR8>rcUYuqdqihgH0>cMw@EXCZjeRwZ*1YYO77F z)kj8sY}6+KmK3s&B;#-x>9Ng8D)2^{F34hx?4$Z`4mV?U2oFS3eu|i&4MYv`hVF z({A;Q9^YsK1Q*+o*$nYNQU?^u5Y3>abCOf_-A4BQ_r3&LuTtrE3YWZwi?wGpX5f{@y0>jZ6!(4Rp@?YFg~6T>3&4v486 z*}Ab#f`B?%MEwe)=@b$2Tde2`p;OV*O|X3(uyvYlD$@Lp&Fgeq2X!+Wviya;>*h9n z2LW^o*$OZvS!WuZ<Tr0)h6B8Q_eKMZG=0wj_hsHB=Te+ zweqyIG0N%&!&W|;p3k-gpEmk5qq|2o1i!WRL!?Mz^YqBZX8SVoxxmpO-NVs6_31_z zJGz%X!{HpxWh#u6W#pv}E1!8q`AnmGJGzhV>*#)bAX1jsrsbf?vt~0{({OWie_i5m z9=A67Oh=!k2QcMD=9}!u6)kf640QC_{FS2z>A?=SVJK+`q<8c=dZ?q%)#pJjM-S7( z9eutY;pmb20;5YEJxX8b=+XLgrh-Va$&8HgIav

x&#cMvry$I6c(pGDnZ+15m7^ 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 PTdH1GOY3`4we)`gyz#i3 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class index 97a809b53396eabe2efe1086b896f97291cc9040..e8e38065a243a964ddb4fd2ecca5b25841728727 100644 GIT binary patch delta 13 UcmdnbzMp+V4l|?7}xbu~mvnH7d=g(v8aSt4x(8 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 F{||t2^D+Pc delta 9454 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1$1.class index 185607a49fd488a9be2d8a8856622980e432d8de..66d9acaf192621175a8b1f3e3e4e73cb8f1d4e5a 100644 GIT binary patch delta 13 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

SL_>Zx|f+z)ELQk=*V!PCP$U{q9ZVlvnn7rJX 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 YQFGNix3^R+Qx7LbS7SzeUbSlQKTgok=l}o! 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 a5e87c356..d21533e20 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 @@ -53,10 +53,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; @@ -213,6 +214,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { clipboard.setOrigin(origin); + Set unknownBlocks = new HashSet<>(); for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { for (int z = 0; z < length; ++z) { @@ -230,9 +232,13 @@ public class MCEditSchematicReader extends NBTSchematicReader { } else { clipboard.setBlock(region.getMinimumPoint().add(pt), state); } - } else { - if (!useOverride) { - log.warn("Unknown block when pasting schematic: " + blocks[index] + ":" + blockData[index] + ". Please report this issue."); + } else if (!useOverride) { + short block = blocks[index]; + byte data = blockData[index]; + int combined = block << 8 | data; + if (unknownBlocks.add(combined)) { + log.warn("Unknown block when pasting schematic: " + + block + ":" + data + ". Please report this issue."); } } } catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this @@ -316,7 +322,6 @@ public class MCEditSchematicReader extends NBTSchematicReader { case "PigZombie": return "zombie_pigman"; default: return id; } - return id; } private String convertBlockEntityId(String id) { From 648ecf2153718b5cccb49c6534940dad2321a608 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 25 Apr 2019 20:48:15 -0400 Subject: [PATCH 069/366] Add entity, biome, and mask flags to clipboard brush. --- .../worldedit/command/BrushCommands.java | 7 ++--- .../worldedit/command/ClipboardCommands.java | 10 +++---- .../command/tool/brush/ClipboardBrush.java | 26 ++++++++++++++++--- .../function/biome/ExtentBiomeCopy.java | 3 +-- .../sk89q/worldedit/session/PasteBuilder.java | 4 +++ 5 files changed, 36 insertions(+), 14 deletions(-) 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 26fcf4d92..450bf5f51 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 @@ -131,7 +131,7 @@ public class BrushCommands { @Command( aliases = { "clipboard", "copy" }, usage = "", - flags = "ap", + flags = "aoebm", desc = "Choose the clipboard brush", help = "Chooses the clipboard brush.\n" + @@ -141,7 +141,8 @@ public class BrushCommands { "stood relative to the copied area when you copied it." ) @CommandPermissions("worldedit.brush.clipboard") - public void clipboardBrush(Player player, LocalSession session, @Switch('a') boolean ignoreAir, @Switch('p') boolean usingOrigin) throws WorldEditException { + public void clipboardBrush(Player player, LocalSession session, @Switch('a') boolean ignoreAir, @Switch('o') boolean usingOrigin, + @Switch('e') boolean pasteEntities, @Switch('b') boolean pasteBiomes, @Switch('m') Mask sourceMask) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); Clipboard clipboard = holder.getClipboard(); @@ -152,7 +153,7 @@ public class BrushCommands { worldEdit.checkMaxBrushRadius(size.getBlockZ() / 2D - 1); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); - tool.setBrush(new ClipboardBrush(holder, ignoreAir, usingOrigin), "worldedit.brush.clipboard"); + tool.setBrush(new ClipboardBrush(holder, ignoreAir, usingOrigin, pasteEntities, pasteBiomes, sourceMask), "worldedit.brush.clipboard"); player.print("Clipboard brush shape equipped."); } 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 cffdbb2ce..7c242011f 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 @@ -170,16 +170,14 @@ public class ClipboardCommands { Region region = clipboard.getRegion(); BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player); - PasteBuilder builder = holder + Operation operation = holder .createPaste(editSession) .to(to) .ignoreAirBlocks(ignoreAirBlocks) .copyBiomes(pasteBiomes) - .copyEntities(pasteEntities); - if (sourceMask != null) { - builder.maskSource(sourceMask); - } - Operation operation = builder.build(); + .copyEntities(pasteEntities) + .maskSource(sourceMask) + .build(); Operations.completeLegacy(operation); if (selectPasted) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java index d6abe3cc9..bbb489242 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/ClipboardBrush.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.command.tool.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; @@ -31,14 +32,30 @@ import com.sk89q.worldedit.session.ClipboardHolder; public class ClipboardBrush implements Brush { - private ClipboardHolder holder; - private boolean ignoreAirBlocks; - private boolean usingOrigin; + private final ClipboardHolder holder; + private final boolean ignoreAirBlocks; + private final boolean usingOrigin; + private final boolean pasteEntities; + private final boolean pasteBiomes; + private final Mask sourceMask; public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks, boolean usingOrigin) { this.holder = holder; this.ignoreAirBlocks = ignoreAirBlocks; this.usingOrigin = usingOrigin; + this.pasteBiomes = false; + this.pasteEntities = false; + this.sourceMask = null; + } + + public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks, boolean usingOrigin, boolean pasteEntities, + boolean pasteBiomes, Mask sourceMask) { + this.holder = holder; + this.ignoreAirBlocks = ignoreAirBlocks; + this.usingOrigin = usingOrigin; + this.pasteEntities = pasteEntities; + this.pasteBiomes = pasteBiomes; + this.sourceMask = sourceMask; } @Override @@ -51,6 +68,9 @@ public class ClipboardBrush implements Brush { .createPaste(editSession) .to(usingOrigin ? position : position.subtract(centerOffset)) .ignoreAirBlocks(ignoreAirBlocks) + .copyEntities(pasteEntities) + .copyBiomes(pasteBiomes) + .maskSource(sourceMask) .build(); Operations.completeLegacy(operation); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java index 43dbf984d..fa1ee8b34 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/ExtentBiomeCopy.java @@ -23,7 +23,6 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.FlatRegionFunction; import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.world.biome.BiomeType; @@ -32,7 +31,7 @@ import static com.google.common.base.Preconditions.checkNotNull; /** * Copies the biome from one extent to another. */ -public class ExtentBiomeCopy implements FlatRegionFunction { +public class ExtentBiomeCopy implements FlatRegionFunction { private final Extent source; private final Extent destination; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java index c46939661..30966535f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/PasteBuilder.java @@ -83,6 +83,10 @@ public class PasteBuilder { * @return this builder instance */ public PasteBuilder maskSource(Mask sourceMask) { + if (sourceMask == null) { + this.sourceMask = Masks.alwaysTrue(); + return this; + } this.sourceMask = sourceMask; return this; } From 302cd8f348ae000446b3d21dceeab55ca4937c7a Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Fri, 26 Apr 2019 16:37:49 +1000 Subject: [PATCH 070/366] Update note in ForgePlatform on data version. --- .../src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index d578c3b9f..6175b865f 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -66,7 +66,7 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { @Override public int getDataVersion() { - // TODO technically available as WorldInfo#field_209227_p but requires a world ref? + // TODO switch to SharedConstants in 1.14 return 1631; } From b8c120e0c409d49f3e716ea30ecf3d69c3efc6dd Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Fri, 26 Apr 2019 01:18:02 -0700 Subject: [PATCH 071/366] Finish porting commands --- .../worldedit/bukkit/WorldEditListener.java | 4 +- .../worldedit/command/ApplyBrushCommands.java | 113 +++++++++++++++++ .../worldedit/command/BrushCommands.java | 114 ++++++++++++++++- .../worldedit/command/PaintBrushCommands.java | 119 ++++++++++++++++++ .../worldedit/command/WorldEditCommands.java | 2 +- ...rnConverter.java => FactoryConverter.java} | 28 ++++- .../command/argument/ItemParser.java | 82 ------------ .../command/argument/ItemUseParser.java | 90 ------------- .../command/argument/MaskConverter.java | 78 ------------ .../argument/RegionFactoryConverter.java | 72 +++++++++++ .../argument/RegionFunctionParser.java | 40 ------ .../command/argument/ReplaceParser.java | 78 ------------ .../command/composition/ApplyCommand.java | 68 ---------- .../command/composition/PaintCommand.java | 64 ---------- .../command/composition/SelectionCommand.java | 2 +- .../composition/ShapedBrushCommand.java | 2 +- .../command/factory/ItemUseFactory.java | 28 +++++ .../command/factory/ReplaceFactory.java | 30 +++++ .../command/factory/TreeGeneratorFactory.java | 25 ++++ .../command/util/PermissionCondition.java | 2 +- .../command/util/PrintCommandHelp.java | 2 +- .../extension/platform/Capability.java | 4 +- ...anger.java => PlatformCommandManager.java} | 88 +++++-------- .../extension/platform/PlatformManager.java | 8 +- .../worldedit/function/ItemUseFunction.java | 23 ++++ .../worldedit/util/command/CommandUtil.java | 33 ++++- 26 files changed, 618 insertions(+), 581 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java rename worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/{PatternConverter.java => FactoryConverter.java} (67%) delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemParser.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemUseParser.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFunctionParser.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ReplaceParser.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ApplyCommand.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/PaintCommand.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java rename worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/{PlatformCommandMananger.java => PlatformCommandManager.java} (86%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java index 699263d50..7eea4312b 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java @@ -91,7 +91,7 @@ public class WorldEditListener implements Listener { if (split.length > 0) { split[0] = split[0].substring(1); - split = plugin.getWorldEdit().getPlatformManager().getPlatformCommandMananger().commandDetection(split); + split = plugin.getWorldEdit().getPlatformManager().getPlatformCommandManager().commandDetection(split); } final String newMessage = "/" + StringUtil.joinString(split, " "); @@ -118,7 +118,7 @@ public class WorldEditListener implements Listener { CommandParameters parameters = NoInputCommandParameters.builder() .injectedValues(MemoizingValueAccess.wrap(store)) .build(); - CommandManager commandManager = plugin.getWorldEdit().getPlatformManager().getPlatformCommandMananger().getCommandManager(); + CommandManager commandManager = plugin.getWorldEdit().getPlatformManager().getPlatformCommandManager().getCommandManager(); event.getCommands().removeIf(name -> // remove if in the manager and not satisfied commandManager.getCommand(name) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java new file mode 100644 index 000000000..2e9297b24 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java @@ -0,0 +1,113 @@ +package com.sk89q.worldedit.command; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; +import com.sk89q.worldedit.command.factory.ItemUseFactory; +import com.sk89q.worldedit.command.factory.ReplaceFactory; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.factory.Apply; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.regions.factory.RegionFactory; +import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.command.CommandUtil; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.DefaultCommandManagerService; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.part.CommandArgument; +import org.enginehub.piston.part.SubCommandPart; + +import java.util.stream.Collectors; + +import static java.util.Objects.requireNonNull; +import static org.enginehub.piston.part.CommandParts.arg; + +@CommandContainer +public class ApplyBrushCommands { + + private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("regionFactory"), TextComponent.of("The shape of the region")) + .defaultsTo(ImmutableList.of()) + .ofTypes(ImmutableList.of(Key.of(RegionFactory.class))) + .build(); + + private static final CommandArgument RADIUS = arg(TranslatableComponent.of("radius"), TextComponent.of("The size of the brush")) + .defaultsTo(ImmutableList.of("5")) + .ofTypes(ImmutableList.of(Key.of(double.class))) + .build(); + + public static void register(CommandManager commandManager) { + commandManager.register("apply", builder -> { + builder.description(TextComponent.of("Apply brush, apply a function to every block")); + builder.action(org.enginehub.piston.Command.Action.NULL_ACTION); + + CommandManager manager = DefaultCommandManagerService.getInstance() + .newCommandManager(); + CommandUtil.register( + manager, + ApplyBrushCommandsRegistration.builder(), + new ApplyBrushCommands() + ); + + builder.condition(new PermissionCondition(ImmutableSet.of("worldedit.brush.apply"))); + + builder.addParts(REGION_FACTORY, RADIUS); + builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TextComponent.of("Type of brush to use")) + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .build()); + }); + } + + private void setApplyBrush(CommandParameters parameters, Player player, LocalSession localSession, + Contextual generatorFactory) throws WorldEditException { + double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class)); + RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class); + BrushCommands.setOperationBasedBrush(player, localSession, radius, + new Apply(generatorFactory), regionFactory, "worldedit.brush.apply"); + } + + @Command( + name = "forest", + desc = "Plant trees" + ) + public void forest(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The type of tree to plant") + TreeGenerator.TreeType type) throws WorldEditException { + setApplyBrush(parameters, player, localSession, new TreeGeneratorFactory(type)); + } + + @Command( + name = "item", + desc = "Use an item" + ) + public void item(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The type of item to use") + BaseItem item) throws WorldEditException { + setApplyBrush(parameters, player, localSession, new ItemUseFactory(item)); + } + + @Command( + name = "set", + desc = "Place a block" + ) + public void set(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The pattern of blocks to use") + Pattern pattern) throws WorldEditException { + setApplyBrush(parameters, player, localSession, new ReplaceFactory(pattern)); + } + +} 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 e310f136a..ebc2e9e5a 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 @@ -23,6 +23,8 @@ import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.factory.ReplaceFactory; +import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.command.tool.brush.ButcherBrush; import com.sk89q.worldedit.command.tool.brush.ClipboardBrush; @@ -30,6 +32,7 @@ import com.sk89q.worldedit.command.tool.brush.CylinderBrush; import com.sk89q.worldedit.command.tool.brush.GravityBrush; import com.sk89q.worldedit.command.tool.brush.HollowCylinderBrush; import com.sk89q.worldedit.command.tool.brush.HollowSphereBrush; +import com.sk89q.worldedit.command.tool.brush.OperationFactoryBrush; import com.sk89q.worldedit.command.tool.brush.SmoothBrush; import com.sk89q.worldedit.command.tool.brush.SphereBrush; import com.sk89q.worldedit.command.util.CommandPermissions; @@ -37,14 +40,21 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CreatureButcher; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.factory.Apply; +import com.sk89q.worldedit.function.factory.Deform; +import com.sk89q.worldedit.function.factory.Paint; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.factory.RegionFactory; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.block.BlockTypes; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; @@ -215,7 +225,7 @@ public class BrushCommands { player.print(String.format("Gravity brush equipped (%.0f).", radius)); } - + @Command( name = "butcher", aliases = { "kill" }, @@ -275,4 +285,106 @@ public class BrushCommands { player.print(String.format("Butcher brush equipped (%.0f).", radius)); } + + @Command( + name = "deform", + desc = "Deform brush, applies an expression to an area" + ) + @CommandPermissions("worldedit.brush.deform") + public void deform(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory regionFactory, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Arg(desc = "Expression to apply", def = "y-=0.2") + String expression, + @Switch(name = 'r', desc = "Use the game's coordinate origin") + boolean useRawCoords, + @Switch(name = 'o', desc = "Use the placement position as the origin") + boolean usePlacement) throws WorldEditException { + Deform deform = new Deform(expression); + if (useRawCoords) { + deform.setMode(Deform.Mode.RAW_COORD); + } else if (usePlacement) { + deform.setMode(Deform.Mode.OFFSET); + deform.setOffset(localSession.getPlacementPosition(player).toVector3()); + } + setOperationBasedBrush(player, localSession, radius, + deform, regionFactory, "worldedit.brush.deform"); + } + + @Command( + name = "set", + desc = "Set brush, sets all blocks in the area" + ) + @CommandPermissions("worldedit.brush.set") + public void set(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory regionFactory, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Arg(desc = "The pattern of blocks to set") + Pattern pattern) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Apply(new ReplaceFactory(pattern)), regionFactory, "worldedit.brush.set"); + } + + @Command( + name = "forest", + desc = "Forest brush, creates a forest in the area" + ) + @CommandPermissions("worldedit.brush.forest") + public void forest(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory regionFactory, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Arg(desc = "The density of the brush", def = "20") + double density, + @Arg(desc = "The type of tree to use") + TreeGenerator.TreeType type) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Paint(new TreeGeneratorFactory(type), density / 100), regionFactory, "worldedit.brush.forest"); + } + + @Command( + name = "raise", + desc = "Raise brush, raise all blocks by one" + ) + @CommandPermissions("worldedit.brush.raise") + public void raise(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory regionFactory, + @Arg(desc = "The size of the brush", def = "5") + double radius) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Deform("y-=1"), regionFactory, "worldedit.brush.raise"); + } + + @Command( + name = "lower", + desc = "Lower brush, lower all blocks by one" + ) + @CommandPermissions("worldedit.brush.lower") + public void lower(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory regionFactory, + @Arg(desc = "The size of the brush", def = "5") + double radius) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Deform("y+=1"), regionFactory, "worldedit.brush.lower"); + } + + static void setOperationBasedBrush(Player player, LocalSession session, double radius, + Contextual factory, + RegionFactory regionFactory, + String permission) throws WorldEditException { + WorldEdit.getInstance().checkMaxBrushRadius(radius); + BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + tool.setSize(radius); + tool.setFill(null); + tool.setBrush(new OperationFactoryBrush(factory, regionFactory, session), permission); + + player.print("Set brush to " + factory); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java new file mode 100644 index 000000000..649c2988b --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java @@ -0,0 +1,119 @@ +package com.sk89q.worldedit.command; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; +import com.sk89q.worldedit.command.factory.ItemUseFactory; +import com.sk89q.worldedit.command.factory.ReplaceFactory; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.factory.Paint; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.regions.factory.RegionFactory; +import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.command.CommandUtil; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.DefaultCommandManagerService; +import org.enginehub.piston.annotation.Command; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.part.CommandArgument; +import org.enginehub.piston.part.SubCommandPart; + +import java.util.stream.Collectors; + +import static java.util.Objects.requireNonNull; +import static org.enginehub.piston.part.CommandParts.arg; + +@CommandContainer +public class PaintBrushCommands { + + private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("regionFactory"), TextComponent.of("The shape of the region")) + .defaultsTo(ImmutableList.of()) + .ofTypes(ImmutableList.of(Key.of(RegionFactory.class))) + .build(); + + private static final CommandArgument RADIUS = arg(TranslatableComponent.of("radius"), TextComponent.of("The size of the brush")) + .defaultsTo(ImmutableList.of("5")) + .ofTypes(ImmutableList.of(Key.of(double.class))) + .build(); + + private static final CommandArgument DENSITY = arg(TranslatableComponent.of("density"), TextComponent.of("The density of the brush")) + .defaultsTo(ImmutableList.of("20")) + .ofTypes(ImmutableList.of(Key.of(double.class))) + .build(); + + public static void register(CommandManager commandManager) { + commandManager.register("paint", builder -> { + builder.description(TextComponent.of("Paint brush, apply a function to a surface")); + builder.action(org.enginehub.piston.Command.Action.NULL_ACTION); + + CommandManager manager = DefaultCommandManagerService.getInstance() + .newCommandManager(); + CommandUtil.register( + manager, + PaintBrushCommandsRegistration.builder(), + new PaintBrushCommands() + ); + + builder.condition(new PermissionCondition(ImmutableSet.of("worldedit.brush.paint"))); + + builder.addParts(REGION_FACTORY, RADIUS, DENSITY); + builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TextComponent.of("Type of brush to use")) + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .build()); + }); + } + + private void setPaintBrush(CommandParameters parameters, Player player, LocalSession localSession, + Contextual generatorFactory) throws WorldEditException { + double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class)); + double density = requireNonNull(DENSITY.value(parameters).asSingle(double.class)) / 100; + RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class); + BrushCommands.setOperationBasedBrush(player, localSession, radius, + new Paint(generatorFactory, density), regionFactory, "worldedit.brush.paint"); + } + + @Command( + name = "forest", + desc = "Plant trees" + ) + public void forest(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The type of tree to plant") + TreeGenerator.TreeType type) throws WorldEditException { + setPaintBrush(parameters, player, localSession, new TreeGeneratorFactory(type)); + } + + @Command( + name = "item", + desc = "Use an item" + ) + public void item(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The type of item to use") + BaseItem item) throws WorldEditException { + setPaintBrush(parameters, player, localSession, new ItemUseFactory(item)); + } + + @Command( + name = "set", + desc = "Place a block" + ) + public void set(CommandParameters parameters, + Player player, LocalSession localSession, + @Arg(desc = "The pattern of blocks to use") + Pattern pattern) throws WorldEditException { + setPaintBrush(parameters, player, localSession, new ReplaceFactory(pattern)); + } + +} 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 1b7346cd0..7586b0109 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 @@ -120,7 +120,7 @@ public class WorldEditCommands { actor.checkPermission("worldedit.report.pastebin"); ActorCallbackPaste.pastebin( we.getSupervisor(), actor, result, "WorldEdit report: %s.report", - WorldEdit.getInstance().getPlatformManager().getPlatformCommandMananger().getExceptionConverter() + WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter() ); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java similarity index 67% rename from worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternConverter.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index 4202b4679..2e7eedb72 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/PatternConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -21,12 +21,15 @@ package com.sk89q.worldedit.command.argument; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.registry.AbstractFactory; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.World; @@ -37,20 +40,33 @@ import org.enginehub.piston.converter.SuccessfulConversion; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; -public class PatternConverter implements ArgumentConverter { +import java.util.function.Function; + +public class FactoryConverter implements ArgumentConverter { public static void register(WorldEdit worldEdit, CommandManager commandManager) { - commandManager.registerConverter(Key.of(Pattern.class), new PatternConverter(worldEdit)); + commandManager.registerConverter(Key.of(Pattern.class), + new FactoryConverter<>(worldEdit, WorldEdit::getPatternFactory, "pattern")); + commandManager.registerConverter(Key.of(Mask.class), + new FactoryConverter<>(worldEdit, WorldEdit::getMaskFactory, "mask")); + commandManager.registerConverter(Key.of(BaseItem.class), + new FactoryConverter<>(worldEdit, WorldEdit::getItemFactory, "item")); } private final WorldEdit worldEdit; + private final Function> factoryExtractor; + private final String description; - private PatternConverter(WorldEdit worldEdit) { + private FactoryConverter(WorldEdit worldEdit, + Function> factoryExtractor, + String description) { this.worldEdit = worldEdit; + this.factoryExtractor = factoryExtractor; + this.description = description; } @Override - public ConversionResult convert(String argument, InjectedValueAccess context) { + public ConversionResult convert(String argument, InjectedValueAccess context) { Actor actor = context.injectedValue(Key.of(Actor.class)) .orElseThrow(() -> new IllegalStateException("No actor")); LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); @@ -67,7 +83,7 @@ public class PatternConverter implements ArgumentConverter { try { return SuccessfulConversion.fromSingle( - worldEdit.getPatternFactory().parseFromInput(argument, parserContext) + factoryExtractor.apply(worldEdit).parseFromInput(argument, parserContext) ); } catch (InputParseException e) { throw new IllegalArgumentException(e); @@ -76,6 +92,6 @@ public class PatternConverter implements ArgumentConverter { @Override public Component describeAcceptableArguments() { - return TextComponent.of("any pattern"); + return TextComponent.of("any " + description); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemParser.java deleted file mode 100644 index 880c17fb8..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemParser.java +++ /dev/null @@ -1,82 +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 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.command.argument; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.extension.input.InputParseException; -import com.sk89q.worldedit.extension.input.ParserContext; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.composition.SimpleCommand; -import com.sk89q.worldedit.world.World; - -public class ItemParser extends SimpleCommand { - - private final StringParser stringParser; - - public ItemParser(String name) { - stringParser = addParameter(new StringParser(name, "The item name", null)); - } - - public ItemParser(String name, String defaultSuggestion) { - stringParser = addParameter(new StringParser(name, "The item name", defaultSuggestion)); - } - - @Override - public BaseItem call(CommandArgs args, CommandLocals locals) throws CommandException { - String itemString = stringParser.call(args, locals); - - Actor actor = locals.get(Actor.class); - LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor); - - ParserContext parserContext = new ParserContext(); - parserContext.setActor(actor); - if (actor instanceof Entity) { - Extent extent = ((Entity) actor).getExtent(); - if (extent instanceof World) { - parserContext.setWorld((World) extent); - } - } - parserContext.setSession(session); - - try { - return WorldEdit.getInstance().getItemFactory().parseFromInput(itemString, parserContext); - } catch (InputParseException e) { - throw new CommandException(e.getMessage(), e); - } - } - - @Override - public String getDescription() { - return "Match an item"; - } - - @Override - protected boolean testPermission0(CommandLocals locals) { - return true; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemUseParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemUseParser.java deleted file mode 100644 index f6da447a1..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ItemUseParser.java +++ /dev/null @@ -1,90 +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 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.command.argument; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.function.Contextual; -import com.sk89q.worldedit.function.EditContext; -import com.sk89q.worldedit.function.RegionFunction; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.Direction; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.composition.SimpleCommand; -import com.sk89q.worldedit.world.World; - -public class ItemUseParser extends SimpleCommand> { - - private final ItemParser itemParser = addParameter(new ItemParser("item", "minecraft:bone_meal")); - - @Override - public Contextual call(CommandArgs args, CommandLocals locals) throws CommandException { - BaseItem item = itemParser.call(args, locals); - return new ItemUseFactory(item); - } - - @Override - public String getDescription() { - return "Applies an item"; - } - - @Override - protected boolean testPermission0(CommandLocals locals) { - return true; - } - - private static final class ItemUseFactory implements Contextual { - private final BaseItem item; - - private ItemUseFactory(BaseItem item) { - this.item = item; - } - - @Override - public RegionFunction createFromContext(EditContext input) { - World world = ((EditSession) input.getDestination()).getWorld(); - return new ItemUseFunction(world, item); - } - - @Override - public String toString() { - return "application of the item " + item.getType() + ":" + item.getNbtData(); - } - } - - private static final class ItemUseFunction implements RegionFunction { - private final World world; - private final BaseItem item; - - private ItemUseFunction(World world, BaseItem item) { - this.world = world; - this.item = item; - } - - @Override - public boolean apply(BlockVector3 position) throws WorldEditException { - return world.useItem(position, item, Direction.UP); - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java deleted file mode 100644 index 37e71cbf4..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/MaskConverter.java +++ /dev/null @@ -1,78 +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 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.command.argument; - -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.extension.input.InputParseException; -import com.sk89q.worldedit.extension.input.ParserContext; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.world.World; -import org.enginehub.piston.CommandManager; -import org.enginehub.piston.converter.ArgumentConverter; -import org.enginehub.piston.converter.ConversionResult; -import org.enginehub.piston.converter.FailedConversion; -import org.enginehub.piston.converter.SuccessfulConversion; -import org.enginehub.piston.inject.InjectedValueAccess; -import org.enginehub.piston.inject.Key; - -public class MaskConverter implements ArgumentConverter { - - public static void register(WorldEdit worldEdit, CommandManager commandManager) { - commandManager.registerConverter(Key.of(Mask.class), new MaskConverter(worldEdit)); - } - - private final WorldEdit worldEdit; - - private MaskConverter(WorldEdit worldEdit) { - this.worldEdit = worldEdit; - } - - @Override - public ConversionResult convert(String argument, InjectedValueAccess context) { - Actor actor = context.injectedValue(Key.of(Actor.class)) - .orElseThrow(() -> new IllegalStateException("No actor")); - ParserContext parserContext = new ParserContext(); - parserContext.setActor(actor); - if (actor instanceof Entity) { - Extent extent = ((Entity) actor).getExtent(); - if (extent instanceof World) { - parserContext.setWorld((World) extent); - } - } - parserContext.setSession(worldEdit.getSessionManager().get(actor)); - try { - return SuccessfulConversion.fromSingle( - worldEdit.getMaskFactory().parseFromInput(argument, parserContext) - ); - } catch (InputParseException e) { - return FailedConversion.from(e); - } - } - - @Override - public Component describeAcceptableArguments() { - return TextComponent.of("any mask"); - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java new file mode 100644 index 000000000..ed54327b1 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java @@ -0,0 +1,72 @@ +/* + * 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.command.argument; + +import com.sk89q.worldedit.regions.factory.CuboidRegionFactory; +import com.sk89q.worldedit.regions.factory.CylinderRegionFactory; +import com.sk89q.worldedit.regions.factory.RegionFactory; +import com.sk89q.worldedit.regions.factory.SphereRegionFactory; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +public class RegionFactoryConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(RegionFactory.class), new RegionFactoryConverter()); + } + + private RegionFactoryConverter() { + } + + @Override + public Component describeAcceptableArguments() { + return TextComponent.of("cuboid|sphere|cyl"); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + try { + return SuccessfulConversion.fromSingle(parse(argument)); + } catch (Exception e) { + return FailedConversion.from(e); + } + } + + private RegionFactory parse(String argument) { + switch (argument) { + case "cuboid": + return new CuboidRegionFactory(); + case "sphere": + return new SphereRegionFactory(); + case "cyl": + case "cylinder": + return new CylinderRegionFactory(1); // TODO: Adjustable height + default: + throw new IllegalArgumentException("Not a known region type: " + argument); + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFunctionParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFunctionParser.java deleted file mode 100644 index be96b19bb..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFunctionParser.java +++ /dev/null @@ -1,40 +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 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.command.argument; - -import com.sk89q.worldedit.function.Contextual; -import com.sk89q.worldedit.function.RegionFunction; -import com.sk89q.worldedit.util.command.composition.BranchingCommand; - -public class RegionFunctionParser extends BranchingCommand> { - - public RegionFunctionParser() { - super("functionTpe"); - putOption(new TreeGeneratorParser("treeType"), "forest"); - putOption(new ItemUseParser(), "item"); - putOption(new ReplaceParser(), "set"); - } - - @Override - public String getDescription() { - return "Choose a block function"; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ReplaceParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ReplaceParser.java deleted file mode 100644 index eebfb4a16..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ReplaceParser.java +++ /dev/null @@ -1,78 +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 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.command.argument; - -import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.extent.NullExtent; -import com.sk89q.worldedit.function.Contextual; -import com.sk89q.worldedit.function.EditContext; -import com.sk89q.worldedit.function.RegionFunction; -import com.sk89q.worldedit.function.block.BlockReplace; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.composition.SimpleCommand; - - -public class ReplaceParser extends SimpleCommand> { - - // TODO rewrite for new system -// private final PatternParser fillArg = addParameter(new PatternParser("fillPattern")); - - @Override - public Contextual call(CommandArgs args, CommandLocals locals) throws CommandException { -// Pattern fill = fillArg.call(args, locals); -// return new ReplaceFactory(fill); - return null; - } - - @Override - public String getDescription() { - return "Replaces blocks"; - } - - @Override - protected boolean testPermission0(CommandLocals locals) { - return true; - } - - private static class ReplaceFactory implements Contextual { - private final Pattern fill; - - private ReplaceFactory(Pattern fill) { - this.fill = fill; - } - - @Override - public RegionFunction createFromContext(EditContext context) { - return new BlockReplace( - firstNonNull(context.getDestination(), new NullExtent()), - firstNonNull(context.getFill(), fill)); - } - - @Override - public String toString() { - return "replace blocks"; - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ApplyCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ApplyCommand.java deleted file mode 100644 index a73748e4c..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ApplyCommand.java +++ /dev/null @@ -1,68 +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 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.command.composition; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.command.argument.RegionFunctionParser; -import com.sk89q.worldedit.function.Contextual; -import com.sk89q.worldedit.function.RegionFunction; -import com.sk89q.worldedit.function.factory.Apply; -import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.composition.CommandExecutor; -import com.sk89q.worldedit.util.command.composition.SimpleCommand; - -public class ApplyCommand extends SimpleCommand> { - - private final CommandExecutor> functionParser; - private final String description; - - public ApplyCommand() { - this(new RegionFunctionParser(), "Applies a function to every block"); - } - - public ApplyCommand(CommandExecutor> functionParser, String description) { - checkNotNull(functionParser, "functionParser"); - checkNotNull(description, "description"); - this.functionParser = functionParser; - this.description = description; - addParameter(functionParser); - } - - @Override - public Apply call(CommandArgs args, CommandLocals locals) throws CommandException { - Contextual function = functionParser.call(args, locals); - return new Apply(function); - } - - @Override - public String getDescription() { - return description; - } - - @Override - protected boolean testPermission0(CommandLocals locals) { - return true; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/PaintCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/PaintCommand.java deleted file mode 100644 index 8ce3e004c..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/PaintCommand.java +++ /dev/null @@ -1,64 +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 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.command.composition; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.command.argument.NumberParser; -import com.sk89q.worldedit.command.argument.RegionFunctionParser; -import com.sk89q.worldedit.function.Contextual; -import com.sk89q.worldedit.function.RegionFunction; -import com.sk89q.worldedit.function.factory.Paint; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.composition.CommandExecutor; -import com.sk89q.worldedit.util.command.composition.SimpleCommand; - -public class PaintCommand extends SimpleCommand { - - private final NumberParser densityCommand = addParameter(new NumberParser("density", "0-100", "20")); - private final CommandExecutor> functionParser; - - public PaintCommand() { - this(new RegionFunctionParser()); - } - - public PaintCommand(CommandExecutor> functionParser) { - this.functionParser = functionParser; - addParameter(functionParser); - } - - @Override - public Paint call(CommandArgs args, CommandLocals locals) throws CommandException { - double density = densityCommand.call(args, locals).doubleValue() / 100.0; - Contextual function = functionParser.call(args, locals); - return new Paint(function, density); - } - - @Override - public String getDescription() { - return "Applies a function to surfaces"; - } - - @Override - protected boolean testPermission0(CommandLocals locals) { - return true; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java index dd51c64a2..c0f93463c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java @@ -94,7 +94,7 @@ public class SelectionCommand extends SimpleCommand { return operation; } catch (IncompleteRegionException e) { - WorldEdit.getInstance().getPlatformManager().getPlatformCommandMananger().getExceptionConverter().convert(e); + WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter().convert(e); return null; } } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java index 35fb758a3..911c4080e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java @@ -77,7 +77,7 @@ public class ShapedBrushCommand extends SimpleCommand { tool.setFill(null); tool.setBrush(new OperationFactoryBrush(factory, regionFactory, session), permission); } catch (MaxBrushRadiusException | InvalidToolBindException e) { - WorldEdit.getInstance().getPlatformManager().getPlatformCommandMananger().getExceptionConverter().convert(e); + WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter().convert(e); } player.print("Set brush to " + factory); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java new file mode 100644 index 000000000..33cd470c8 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java @@ -0,0 +1,28 @@ +package com.sk89q.worldedit.command.factory; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.function.ItemUseFunction; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.world.World; + +public final class ItemUseFactory implements Contextual { + private final BaseItem item; + + public ItemUseFactory(BaseItem item) { + this.item = item; + } + + @Override + public RegionFunction createFromContext(EditContext input) { + World world = ((EditSession) input.getDestination()).getWorld(); + return new ItemUseFunction(world, item); + } + + @Override + public String toString() { + return "application of the item " + item.getType() + ":" + item.getNbtData(); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java new file mode 100644 index 000000000..03453fcd7 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java @@ -0,0 +1,30 @@ +package com.sk89q.worldedit.command.factory; + +import com.sk89q.worldedit.extent.NullExtent; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.function.block.BlockReplace; +import com.sk89q.worldedit.function.pattern.Pattern; + +import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull; + +public class ReplaceFactory implements Contextual { + private final Pattern fill; + + public ReplaceFactory(Pattern fill) { + this.fill = fill; + } + + @Override + public RegionFunction createFromContext(EditContext context) { + return new BlockReplace( + firstNonNull(context.getDestination(), new NullExtent()), + firstNonNull(context.getFill(), fill)); + } + + @Override + public String toString() { + return "replace blocks"; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java new file mode 100644 index 000000000..47548b4d5 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java @@ -0,0 +1,25 @@ +package com.sk89q.worldedit.command.factory; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.generator.ForestGenerator; +import com.sk89q.worldedit.util.TreeGenerator; + +public final class TreeGeneratorFactory implements Contextual { + private final TreeGenerator.TreeType type; + + public TreeGeneratorFactory(TreeGenerator.TreeType type) { + this.type = type; + } + + @Override + public ForestGenerator createFromContext(EditContext input) { + return new ForestGenerator((EditSession) input.getDestination(), type); + } + + @Override + public String toString() { + return "tree of type " + type; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java index 4b33675f9..48b6acc16 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java @@ -32,7 +32,7 @@ public final class PermissionCondition implements Command.Condition { private final Set permissions; - PermissionCondition(Set permissions) { + public PermissionCondition(Set permissions) { this.permissions = permissions; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java index 57337b322..b1971b0a9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -74,7 +74,7 @@ public class PrintCommandHelp { actor.printError("Page must be >= 1."); return; } - CommandManager manager = we.getPlatformManager().getPlatformCommandMananger().getCommandManager(); + CommandManager manager = we.getPlatformManager().getPlatformCommandManager().getCommandManager(); final int perPage = actor instanceof Player ? 8 : 20; // More pages for console diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java index 50aa913b4..e91c799bc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java @@ -50,12 +50,12 @@ public enum Capability { USER_COMMANDS { @Override void initialize(PlatformManager platformManager, Platform platform) { - platformManager.getPlatformCommandMananger().register(platform); + platformManager.getPlatformCommandManager().registerCommandsWith(platform); } @Override void unload(PlatformManager platformManager, Platform platform) { - platformManager.getPlatformCommandMananger().unregister(); + platformManager.getPlatformCommandManager().removeCommands(); } }, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java similarity index 86% rename from worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index eb8b4adbc..ed93a11b8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandMananger.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.ApplyBrushCommands; import com.sk89q.worldedit.command.BiomeCommands; import com.sk89q.worldedit.command.BiomeCommandsRegistration; import com.sk89q.worldedit.command.BrushCommands; @@ -42,6 +43,7 @@ import com.sk89q.worldedit.command.HistoryCommands; import com.sk89q.worldedit.command.HistoryCommandsRegistration; import com.sk89q.worldedit.command.NavigationCommands; import com.sk89q.worldedit.command.NavigationCommandsRegistration; +import com.sk89q.worldedit.command.PaintBrushCommands; import com.sk89q.worldedit.command.RegionCommands; import com.sk89q.worldedit.command.RegionCommandsRegistration; import com.sk89q.worldedit.command.SchematicCommands; @@ -71,11 +73,10 @@ import com.sk89q.worldedit.command.argument.DirectionConverter; import com.sk89q.worldedit.command.argument.EntityRemoverConverter; import com.sk89q.worldedit.command.argument.EnumConverter; import com.sk89q.worldedit.command.argument.ExpandAmountConverter; -import com.sk89q.worldedit.command.argument.MaskConverter; -import com.sk89q.worldedit.command.argument.PatternConverter; +import com.sk89q.worldedit.command.argument.FactoryConverter; +import com.sk89q.worldedit.command.argument.RegionFactoryConverter; import com.sk89q.worldedit.command.argument.VectorConverter; import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter; -import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; @@ -83,7 +84,6 @@ import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.annotation.Selection; -import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; @@ -102,7 +102,6 @@ import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.CommandExecutionException; import org.enginehub.piston.exception.ConditionFailedException; import org.enginehub.piston.exception.UsageException; -import org.enginehub.piston.gen.CommandCallListener; import org.enginehub.piston.gen.CommandRegistration; import org.enginehub.piston.inject.InjectedValueStore; import org.enginehub.piston.inject.Key; @@ -116,29 +115,28 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; -import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.function.Consumer; import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.regex.Pattern; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.util.command.CommandUtil.COMMAND_LOG; +import static com.sk89q.worldedit.util.command.CommandUtil.register; /** * Handles the registration and invocation of commands. * *

This class is primarily for internal usage.

*/ -public final class PlatformCommandMananger { +public final class PlatformCommandManager { public static final Pattern COMMAND_CLEAN_PATTERN = Pattern.compile("^[/]+"); - private static final Logger log = LoggerFactory.getLogger(PlatformCommandMananger.class); - private static final java.util.logging.Logger commandLog = - java.util.logging.Logger.getLogger(PlatformCommandMananger.class.getCanonicalName() + ".CommandLog"); + private static final Logger log = LoggerFactory.getLogger(PlatformCommandManager.class); private static final Pattern numberFormatExceptionPattern = Pattern.compile("^For input string: \"(.*)\"$"); - private static final CommandPermissionsConditionGenerator PERM_GEN = new CommandPermissionsConditionGenerator(); private final WorldEdit worldEdit; private final PlatformManager platformManager; @@ -146,14 +144,13 @@ public final class PlatformCommandMananger { private final InjectedValueStore globalInjectedValues; private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler(); private final WorldEditExceptionConverter exceptionConverter; - private final List callListeners; /** * Create a new instance. * * @param worldEdit the WorldEdit instance */ - PlatformCommandMananger(final WorldEdit worldEdit, PlatformManager platformManager) { + PlatformCommandManager(final WorldEdit worldEdit, PlatformManager platformManager) { checkNotNull(worldEdit); checkNotNull(platformManager); this.worldEdit = worldEdit; @@ -162,32 +159,17 @@ public final class PlatformCommandMananger { this.commandManager = DefaultCommandManagerService.getInstance() .newCommandManager(); this.globalInjectedValues = MapBackedValueStore.create(); - this.callListeners = Collections.singletonList( - new CommandLoggingHandler(worldEdit, commandLog) - ); // setup separate from main constructor // ensures that everything is definitely assigned initialize(); } - private void register(CommandManager manager, CommandRegistration registration, CI instance) { - registration.containerInstance(instance) - .commandManager(manager) - .listeners(callListeners); - if (registration instanceof CommandPermissionsConditionGenerator.Registration) { - ((CommandPermissionsConditionGenerator.Registration) registration).commandPermissionsConditionGenerator( - PERM_GEN - ); - } - registration.build(); - } - private void initialize() { // Register this instance for command events worldEdit.getEventBus().register(this); // Setup the logger - commandLog.addHandler(dynamicHandler); + COMMAND_LOG.addHandler(dynamicHandler); // Set up the commands manager registerAlwaysInjectedValues(); @@ -197,8 +179,7 @@ public final class PlatformCommandMananger { private void registerArgumentConverters() { DirectionConverter.register(worldEdit, commandManager); - MaskConverter.register(worldEdit, commandManager); - PatternConverter.register(worldEdit, commandManager); + FactoryConverter.register(worldEdit, commandManager); for (int count = 2; count <= 3; count++) { commandManager.registerConverter(Key.of(double.class, Annotations.radii(count)), CommaSeparatedValuesConverter.wrapAndLimit(ArgumentConverters.get( @@ -212,6 +193,7 @@ public final class PlatformCommandMananger { ZonedDateTimeConverter.register(commandManager); BooleanConverter.register(commandManager); EntityRemoverConverter.register(commandManager); + RegionFactoryConverter.register(commandManager); } private void registerAlwaysInjectedValues() { @@ -243,7 +225,13 @@ public final class PlatformCommandMananger { } private void registerSubCommands(String name, List aliases, String desc, - CommandRegistration registration, CI instance) { + CommandRegistration registration, CI instance) { + registerSubCommands(name, aliases, desc, registration, instance, m -> {}); + } + + private void registerSubCommands(String name, List aliases, String desc, + CommandRegistration registration, CI instance, + Consumer additionalConfig) { commandManager.register(name, cmd -> { cmd.aliases(aliases); cmd.description(TextComponent.of(desc)); @@ -292,7 +280,11 @@ public final class PlatformCommandMananger { ImmutableList.of("br"), "Brushing commands", BrushCommandsRegistration.builder(), - new BrushCommands(worldEdit) + new BrushCommands(worldEdit), + manager -> { + PaintBrushCommands.register(manager); + ApplyBrushCommands.register(manager); + } ); registerSubCommands( "worldedit", @@ -371,31 +363,13 @@ public final class PlatformCommandMananger { UtilityCommandsRegistration.builder(), new UtilityCommands(worldEdit) ); - - // Unported commands are below. Delete once they're added to the main manager above. - /* - dispatcher = new CommandGraph() - .builder(builder) - .commands() - .group("brush", "br") - .describeAs("Brushing commands") - .register(adapt(new ShapedBrushCommand(new DeformCommand(), "worldedit.brush.deform")), "deform") - .register(adapt(new ShapedBrushCommand(new ApplyCommand(new ReplaceParser(), "Set all blocks within region"), "worldedit.brush.set")), "set") - .register(adapt(new ShapedBrushCommand(new PaintCommand(), "worldedit.brush.paint")), "paint") - .register(adapt(new ShapedBrushCommand(new ApplyCommand(), "worldedit.brush.apply")), "apply") - .register(adapt(new ShapedBrushCommand(new PaintCommand(new TreeGeneratorParser("treeType")), "worldedit.brush.forest")), "forest") - .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y-=1", Mode.RAW_COORD), "Raise one block"), "worldedit.brush.raise")), "raise") - .register(adapt(new ShapedBrushCommand(ProvidedValue.create(new Deform("y+=1", Mode.RAW_COORD), "Lower one block"), "worldedit.brush.lower")), "lower") - .parent() - .getDispatcher(); - */ } public ExceptionConverter getExceptionConverter() { return exceptionConverter; } - void register(Platform platform) { + void registerCommandsWith(Platform platform) { log.info("Registering commands with " + platform.getClass().getCanonicalName()); LocalConfiguration config = platform.getConfiguration(); @@ -405,10 +379,10 @@ public final class PlatformCommandMananger { // Register log if (!logging || path.isEmpty()) { dynamicHandler.setHandler(null); - commandLog.setLevel(Level.OFF); + COMMAND_LOG.setLevel(Level.OFF); } else { File file = new File(config.getWorkingDirectory(), path); - commandLog.setLevel(Level.ALL); + COMMAND_LOG.setLevel(Level.ALL); log.info("Logging WorldEdit commands to " + file.getAbsolutePath()); @@ -424,7 +398,7 @@ public final class PlatformCommandMananger { platform.registerCommands(commandManager); } - void unregister() { + void removeCommands() { dynamicHandler.setHandler(null); } @@ -581,8 +555,4 @@ public final class PlatformCommandMananger { return commandManager; } - public static java.util.logging.Logger getLogger() { - return commandLog; - } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index 692c1558e..f37c9b4a5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -68,7 +68,7 @@ public class PlatformManager { private static final Logger logger = LoggerFactory.getLogger(PlatformManager.class); private final WorldEdit worldEdit; - private final PlatformCommandMananger platformCommandMananger; + private final PlatformCommandManager platformCommandManager; private final List platforms = new ArrayList<>(); private final Map preferences = new EnumMap<>(Capability.class); private @Nullable String firstSeenVersion; @@ -83,7 +83,7 @@ public class PlatformManager { public PlatformManager(WorldEdit worldEdit) { checkNotNull(worldEdit); this.worldEdit = worldEdit; - this.platformCommandMananger = new PlatformCommandMananger(worldEdit, this); + this.platformCommandManager = new PlatformCommandManager(worldEdit, this); // Register this instance for events worldEdit.getEventBus().register(this); @@ -277,8 +277,8 @@ public class PlatformManager { * * @return the command manager */ - public PlatformCommandMananger getPlatformCommandMananger() { - return platformCommandMananger; + public PlatformCommandManager getPlatformCommandManager() { + return platformCommandManager; } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java new file mode 100644 index 000000000..b3b8e4748 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java @@ -0,0 +1,23 @@ +package com.sk89q.worldedit.function; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.World; + +public final class ItemUseFunction implements RegionFunction { + private final World world; + private final BaseItem item; + + public ItemUseFunction(World world, BaseItem item) { + this.world = world; + this.item = item; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + return world.useItem(position, item, Direction.UP); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java index c583add43..ccf702e16 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java @@ -19,13 +19,22 @@ package com.sk89q.worldedit.util.command; -import com.sk89q.worldedit.extension.platform.PlatformCommandMananger; +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.extension.platform.PlatformCommandManager; +import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.gen.CommandCallListener; +import org.enginehub.piston.gen.CommandRegistration; import org.enginehub.piston.part.SubCommandPart; import java.util.Comparator; +import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.logging.Logger; import java.util.stream.Collectors; public class CommandUtil { @@ -38,7 +47,7 @@ public class CommandUtil { } private static String clean(String input) { - return PlatformCommandMananger.COMMAND_CLEAN_PATTERN.matcher(input).replaceAll(""); + return PlatformCommandManager.COMMAND_CLEAN_PATTERN.matcher(input).replaceAll(""); } private static final Comparator BY_CLEAN_NAME = @@ -48,6 +57,26 @@ public class CommandUtil { return BY_CLEAN_NAME; } + private static final CommandPermissionsConditionGenerator PERM_GEN = new CommandPermissionsConditionGenerator(); + + public static final Logger COMMAND_LOG = + Logger.getLogger("com.sk89q.worldedit.CommandLog"); + private static final List CALL_LISTENERS = ImmutableList.of( + new CommandLoggingHandler(WorldEdit.getInstance(), COMMAND_LOG) + ); + + public static void register(CommandManager manager, CommandRegistration registration, CI instance) { + registration.containerInstance(instance) + .commandManager(manager) + .listeners(CALL_LISTENERS); + if (registration instanceof CommandPermissionsConditionGenerator.Registration) { + ((CommandPermissionsConditionGenerator.Registration) registration).commandPermissionsConditionGenerator( + PERM_GEN + ); + } + registration.build(); + } + private CommandUtil() { } } From 23279c007eab9e0897976861619751f6466786fc Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Fri, 26 Apr 2019 01:38:06 -0700 Subject: [PATCH 072/366] Fix intialization, rework registration --- .../worldedit/command/ApplyBrushCommands.java | 27 ++++++++-- .../worldedit/command/PaintBrushCommands.java | 27 ++++++++-- .../command/factory/ItemUseFactory.java | 19 +++++++ .../command/factory/ReplaceFactory.java | 19 +++++++ .../command/factory/TreeGeneratorFactory.java | 19 +++++++ .../platform/PlatformCommandManager.java | 45 +++++++++------- .../worldedit/function/ItemUseFunction.java | 19 +++++++ .../command/CommandRegistrationHandler.java | 54 +++++++++++++++++++ .../worldedit/util/command/CommandUtil.java | 29 ---------- 9 files changed, 202 insertions(+), 56 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandRegistrationHandler.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java index 2e9297b24..d324c3484 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java @@ -1,3 +1,22 @@ +/* + * 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.command; import com.google.common.collect.ImmutableList; @@ -5,9 +24,9 @@ import com.google.common.collect.ImmutableSet; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; import com.sk89q.worldedit.command.factory.ItemUseFactory; import com.sk89q.worldedit.command.factory.ReplaceFactory; +import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.Contextual; @@ -16,7 +35,7 @@ import com.sk89q.worldedit.function.factory.Apply; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.factory.RegionFactory; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.command.CommandUtil; +import com.sk89q.worldedit.util.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import org.enginehub.piston.CommandManager; @@ -47,14 +66,14 @@ public class ApplyBrushCommands { .ofTypes(ImmutableList.of(Key.of(double.class))) .build(); - public static void register(CommandManager commandManager) { + public static void register(CommandManager commandManager, CommandRegistrationHandler registration) { commandManager.register("apply", builder -> { builder.description(TextComponent.of("Apply brush, apply a function to every block")); builder.action(org.enginehub.piston.Command.Action.NULL_ACTION); CommandManager manager = DefaultCommandManagerService.getInstance() .newCommandManager(); - CommandUtil.register( + registration.register( manager, ApplyBrushCommandsRegistration.builder(), new ApplyBrushCommands() diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java index 649c2988b..c365e129f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java @@ -1,3 +1,22 @@ +/* + * 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.command; import com.google.common.collect.ImmutableList; @@ -5,9 +24,9 @@ import com.google.common.collect.ImmutableSet; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; import com.sk89q.worldedit.command.factory.ItemUseFactory; import com.sk89q.worldedit.command.factory.ReplaceFactory; +import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.Contextual; @@ -16,7 +35,7 @@ import com.sk89q.worldedit.function.factory.Paint; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.factory.RegionFactory; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.command.CommandUtil; +import com.sk89q.worldedit.util.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import org.enginehub.piston.CommandManager; @@ -52,14 +71,14 @@ public class PaintBrushCommands { .ofTypes(ImmutableList.of(Key.of(double.class))) .build(); - public static void register(CommandManager commandManager) { + public static void register(CommandManager commandManager, CommandRegistrationHandler registration) { commandManager.register("paint", builder -> { builder.description(TextComponent.of("Paint brush, apply a function to a surface")); builder.action(org.enginehub.piston.Command.Action.NULL_ACTION); CommandManager manager = DefaultCommandManagerService.getInstance() .newCommandManager(); - CommandUtil.register( + registration.register( manager, PaintBrushCommandsRegistration.builder(), new PaintBrushCommands() diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java index 33cd470c8..8b25780d4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java @@ -1,3 +1,22 @@ +/* + * 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.command.factory; import com.sk89q.worldedit.EditSession; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java index 03453fcd7..4c1797b52 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ReplaceFactory.java @@ -1,3 +1,22 @@ +/* + * 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.command.factory; import com.sk89q.worldedit.extent.NullExtent; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java index 47548b4d5..76d875851 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/TreeGeneratorFactory.java @@ -1,3 +1,22 @@ +/* + * 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.command.factory; import com.sk89q.worldedit.EditSession; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index ed93a11b8..b8e5f2101 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -84,9 +84,11 @@ import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.annotation.Selection; +import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -124,8 +126,6 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.util.command.CommandUtil.COMMAND_LOG; -import static com.sk89q.worldedit.util.command.CommandUtil.register; /** * Handles the registration and invocation of commands. @@ -136,6 +136,8 @@ public final class PlatformCommandManager { public static final Pattern COMMAND_CLEAN_PATTERN = Pattern.compile("^[/]+"); private static final Logger log = LoggerFactory.getLogger(PlatformCommandManager.class); + private static final java.util.logging.Logger COMMAND_LOG = + java.util.logging.Logger.getLogger("com.sk89q.worldedit.CommandLog"); private static final Pattern numberFormatExceptionPattern = Pattern.compile("^For input string: \"(.*)\"$"); private final WorldEdit worldEdit; @@ -144,6 +146,7 @@ public final class PlatformCommandManager { private final InjectedValueStore globalInjectedValues; private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler(); private final WorldEditExceptionConverter exceptionConverter; + private final CommandRegistrationHandler registration; /** * Create a new instance. @@ -159,6 +162,10 @@ public final class PlatformCommandManager { this.commandManager = DefaultCommandManagerService.getInstance() .newCommandManager(); this.globalInjectedValues = MapBackedValueStore.create(); + this.registration = new CommandRegistrationHandler( + ImmutableList.of( + new CommandLoggingHandler(worldEdit, COMMAND_LOG) + )); // setup separate from main constructor // ensures that everything is definitely assigned initialize(); @@ -239,7 +246,7 @@ public final class PlatformCommandManager { CommandManager manager = DefaultCommandManagerService.getInstance() .newCommandManager(); - register( + this.registration.register( manager, registration, instance @@ -282,8 +289,8 @@ public final class PlatformCommandManager { BrushCommandsRegistration.builder(), new BrushCommands(worldEdit), manager -> { - PaintBrushCommands.register(manager); - ApplyBrushCommands.register(manager); + PaintBrushCommands.register(manager, registration); + ApplyBrushCommands.register(manager, registration); } ); registerSubCommands( @@ -293,72 +300,72 @@ public final class PlatformCommandManager { WorldEditCommandsRegistration.builder(), new WorldEditCommands(worldEdit) ); - register( + this.registration.register( commandManager, BiomeCommandsRegistration.builder(), new BiomeCommands() ); - register( + this.registration.register( commandManager, ChunkCommandsRegistration.builder(), new ChunkCommands(worldEdit) ); - register( + this.registration.register( commandManager, ClipboardCommandsRegistration.builder(), new ClipboardCommands() ); - register( + this.registration.register( commandManager, GeneralCommandsRegistration.builder(), new GeneralCommands(worldEdit) ); - register( + this.registration.register( commandManager, GenerationCommandsRegistration.builder(), new GenerationCommands(worldEdit) ); - register( + this.registration.register( commandManager, HistoryCommandsRegistration.builder(), new HistoryCommands(worldEdit) ); - register( + this.registration.register( commandManager, NavigationCommandsRegistration.builder(), new NavigationCommands(worldEdit) ); - register( + this.registration.register( commandManager, RegionCommandsRegistration.builder(), new RegionCommands() ); - register( + this.registration.register( commandManager, ScriptingCommandsRegistration.builder(), new ScriptingCommands(worldEdit) ); - register( + this.registration.register( commandManager, SelectionCommandsRegistration.builder(), new SelectionCommands(worldEdit) ); - register( + this.registration.register( commandManager, SnapshotUtilCommandsRegistration.builder(), new SnapshotUtilCommands(worldEdit) ); - register( + this.registration.register( commandManager, ToolCommandsRegistration.builder(), new ToolCommands(worldEdit) ); - register( + this.registration.register( commandManager, ToolUtilCommandsRegistration.builder(), new ToolUtilCommands(worldEdit) ); - register( + this.registration.register( commandManager, UtilityCommandsRegistration.builder(), new UtilityCommands(worldEdit) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java index b3b8e4748..4e439f0c3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java @@ -1,3 +1,22 @@ +/* + * 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.function; import com.sk89q.worldedit.WorldEditException; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandRegistrationHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandRegistrationHandler.java new file mode 100644 index 000000000..8e243be98 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandRegistrationHandler.java @@ -0,0 +1,54 @@ +/* + * 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.util.command; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.internal.command.CommandLoggingHandler; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.gen.CommandCallListener; +import org.enginehub.piston.gen.CommandRegistration; + +import java.util.List; +import java.util.logging.Logger; + +public class CommandRegistrationHandler { + + private static final CommandPermissionsConditionGenerator PERM_GEN = new CommandPermissionsConditionGenerator(); + + private final List callListeners; + + public CommandRegistrationHandler(List callListeners) { + this.callListeners = ImmutableList.copyOf(callListeners); + } + + public void register(CommandManager manager, CommandRegistration registration, CI instance) { + registration.containerInstance(instance) + .commandManager(manager) + .listeners(callListeners); + if (registration instanceof CommandPermissionsConditionGenerator.Registration) { + ((CommandPermissionsConditionGenerator.Registration) registration).commandPermissionsConditionGenerator( + PERM_GEN + ); + } + registration.build(); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java index ccf702e16..3d86fbfb9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java @@ -19,22 +19,13 @@ package com.sk89q.worldedit.util.command; -import com.google.common.collect.ImmutableList; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.extension.platform.PlatformCommandManager; -import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import org.enginehub.piston.Command; -import org.enginehub.piston.CommandManager; -import org.enginehub.piston.gen.CommandCallListener; -import org.enginehub.piston.gen.CommandRegistration; import org.enginehub.piston.part.SubCommandPart; import java.util.Comparator; -import java.util.List; import java.util.Map; import java.util.function.Function; -import java.util.logging.Logger; import java.util.stream.Collectors; public class CommandUtil { @@ -57,26 +48,6 @@ public class CommandUtil { return BY_CLEAN_NAME; } - private static final CommandPermissionsConditionGenerator PERM_GEN = new CommandPermissionsConditionGenerator(); - - public static final Logger COMMAND_LOG = - Logger.getLogger("com.sk89q.worldedit.CommandLog"); - private static final List CALL_LISTENERS = ImmutableList.of( - new CommandLoggingHandler(WorldEdit.getInstance(), COMMAND_LOG) - ); - - public static void register(CommandManager manager, CommandRegistration registration, CI instance) { - registration.containerInstance(instance) - .commandManager(manager) - .listeners(CALL_LISTENERS); - if (registration instanceof CommandPermissionsConditionGenerator.Registration) { - ((CommandPermissionsConditionGenerator.Registration) registration).commandPermissionsConditionGenerator( - PERM_GEN - ); - } - registration.build(); - } - private CommandUtil() { } } From 968decf62eebde9ed77143a27edc6fa56e5036ac Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Fri, 26 Apr 2019 23:42:57 +1000 Subject: [PATCH 073/366] Remove the -l lightning flag from butcher --- build.gradle | 2 -- .../sk89q/worldedit/command/BrushCommands.java | 6 +----- .../sk89q/worldedit/command/UtilityCommands.java | 6 +----- .../worldedit/command/util/CreatureButcher.java | 15 --------------- 4 files changed, 2 insertions(+), 27 deletions(-) diff --git a/build.gradle b/build.gradle index 45076d4ed..41de17bb8 100644 --- a/build.gradle +++ b/build.gradle @@ -86,8 +86,6 @@ subprojects { mavenCentral() maven { url "http://maven.sk89q.com/repo/" } maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } - // temporary, for Piston - mavenLocal() } } 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 d187723ba..0b29fdede 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 @@ -257,9 +257,7 @@ public class BrushCommands { @Switch(name = 'f', desc = "Also kill all friendly mobs (Applies the flags `-abgnpt`)") boolean killFriendly, @Switch(name = 'r', desc = "Also destroy armor stands") - boolean killArmorStands, - @Switch(name = 'l', desc = "Kill via lightning. Currently non-functioning.") - boolean killWithLightning) throws WorldEditException { + boolean killArmorStands) throws WorldEditException { LocalConfiguration config = worldEdit.getConfiguration(); double maxRadius = config.maxBrushRadius; @@ -284,8 +282,6 @@ public class BrushCommands { flags.or(CreatureButcher.Flags.TAGGED , killWithName, "worldedit.butcher.tagged"); flags.or(CreatureButcher.Flags.ARMOR_STAND , killArmorStands, "worldedit.butcher.armorstands"); - flags.or(CreatureButcher.Flags.WITH_LIGHTNING, killWithLightning, "worldedit.butcher.lightning"); - BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); tool.setSize(radius); tool.setBrush(new ButcherBrush(flags), "worldedit.brush.butcher"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 12988ab56..ea292a855 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -375,9 +375,7 @@ public class UtilityCommands { @Switch(name = 'f', desc = "Also kill all friendly mobs (Applies the flags `-abgnpt`)") boolean killFriendly, @Switch(name = 'r', desc = "Also destroy armor stands") - boolean killArmorStands, - @Switch(name = 'l', desc = "Kill via lightning. Currently non-functioning.") - boolean killWithLightning) throws WorldEditException { + boolean killArmorStands) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); Player player = actor instanceof Player ? (Player) actor : null; @@ -406,8 +404,6 @@ public class UtilityCommands { flags.or(CreatureButcher.Flags.TAGGED, killWithName, "worldedit.butcher.tagged"); flags.or(CreatureButcher.Flags.ARMOR_STAND, killArmorStands, "worldedit.butcher.armorstands"); - flags.or(CreatureButcher.Flags.WITH_LIGHTNING, killWithLightning, "worldedit.butcher.lightning"); - int killed = killMatchingEntities(radius, player, flags::createFunction); actor.print("Killed " + killed + (killed != 1 ? " mobs" : " mob") + (radius < 0 ? "" : " in a radius of " + radius) + "."); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java index 940d6a99c..e43fee9d4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CreatureButcher.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.command.util; -import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.worldedit.entity.metadata.EntityProperties; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.EntityFunction; @@ -39,7 +38,6 @@ public class CreatureButcher { public static final int TAGGED = 1 << 5; public static final int FRIENDLY = PETS | NPCS | ANIMALS | GOLEMS | AMBIENT | TAGGED; public static final int ARMOR_STAND = 1 << 6; - public static final int WITH_LIGHTNING = 1 << 20; private Flags() { } @@ -64,19 +62,6 @@ public class CreatureButcher { } } - public void fromCommand(CommandContext args) { - or(Flags.FRIENDLY , args.hasFlag('f')); // No permission check here. Flags will instead be filtered by the subsequent calls. - or(Flags.PETS , args.hasFlag('p'), "worldedit.butcher.pets"); - or(Flags.NPCS , args.hasFlag('n'), "worldedit.butcher.npcs"); - or(Flags.GOLEMS , args.hasFlag('g'), "worldedit.butcher.golems"); - or(Flags.ANIMALS , args.hasFlag('a'), "worldedit.butcher.animals"); - or(Flags.AMBIENT , args.hasFlag('b'), "worldedit.butcher.ambient"); - or(Flags.TAGGED , args.hasFlag('t'), "worldedit.butcher.tagged"); - or(Flags.ARMOR_STAND , args.hasFlag('r'), "worldedit.butcher.armorstands"); - - or(Flags.WITH_LIGHTNING, args.hasFlag('l'), "worldedit.butcher.lightning"); - } - public EntityFunction createFunction() { return entity -> { boolean killPets = (flags & Flags.PETS) != 0; From 07ff4e97c1ba53923919c189bea4ce0efb6c37a2 Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 26 Apr 2019 15:08:50 -0400 Subject: [PATCH 074/366] Add logo to source. --- README.md | 2 +- worldedit-logo.png | Bin 0 -> 9124 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 worldedit-logo.png diff --git a/README.md b/README.md index 2cfef0034..6d9968e37 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![WorldEdit](http://static.sk89q.com/readme/worldedit.png) +![WorldEdit](worldedit-logo.png) ========= WorldEdit is Minecraft mod that turns Minecraft into an in-game map editor (sorta, kinda). diff --git a/worldedit-logo.png b/worldedit-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e0b515743ce40641cfdc045b1bc0e9e28dc32fe2 GIT binary patch literal 9124 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 Date: Fri, 26 Apr 2019 21:48:03 -0400 Subject: [PATCH 075/366] Re-add 1.13 entity renames. Accidentally replaced the new ones with the old ones. This is why we need DFUs. --- .../extent/clipboard/io/MCEditSchematicReader.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 d21533e20..53ec62dae 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 @@ -320,6 +320,18 @@ public class MCEditSchematicReader extends NBTSchematicReader { case "ThrownExpBottle": return "xp_bottle"; case "XPOrb": return "xp_orb"; case "PigZombie": return "zombie_pigman"; + case "xp_orb": return "experience_orb"; + case "xp_bottle": return "experience_bottle"; + case "eye_of_ender_signal": return "eye_of_ender"; + case "ender_crystal": return "end_crystal"; + case "fireworks_rocket": return "firework_rocket"; + case "commandblock_minecart": return "command_block_minecart"; + case "snowman": return "snow_golem"; + case "villager_golem": return "iron_golem"; + case "evocation_fangs": return "evoker_fangs"; + case "evocation_illager": return "evoker"; + case "vindication_illager": return "vindicator"; + case "illusion_illager": return "illusioner"; default: return id; } } From f94093239f019c5be4a4d5b692414fdd2a4aa8c5 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 27 Apr 2019 16:46:13 +1000 Subject: [PATCH 076/366] Setup a registry converter --- .../worldedit/command/WorldEditCommands.java | 20 ++-- .../command/argument/NumberParser.java | 6 +- .../command/argument/RegistryConverter.java | 98 +++++++++++++++++++ .../command/argument/StringParser.java | 6 +- .../platform/PlatformCommandManager.java | 2 + 5 files changed, 120 insertions(+), 12 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java 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 7586b0109..0d19d1538 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 @@ -48,6 +48,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.TextStyle; +import java.time.zone.ZoneRulesException; import java.util.List; import java.util.Locale; @@ -68,7 +69,7 @@ public class WorldEditCommands { ) public void version(Actor actor) throws WorldEditException { actor.print("WorldEdit version " + WorldEdit.getVersion()); - actor.print("https://github.com/sk89q/worldedit/"); + actor.print("https://github.com/EngineHub/worldedit/"); PlatformManager pm = we.getPlatformManager(); @@ -141,13 +142,16 @@ public class WorldEditCommands { public void tz(Player player, LocalSession session, @Arg(desc = "The timezone to set") String timezone) throws WorldEditException { - ZoneId tz = ZoneId.of(timezone); - session.setTimezone(tz); - player.print("Timezone set for this session to: " + tz.getDisplayName( - TextStyle.FULL, Locale.ENGLISH - )); - player.print("The current time in that timezone is: " - + dateFormat.format(ZonedDateTime.now(tz))); + try { + ZoneId tz = ZoneId.of(timezone); + session.setTimezone(tz); + player.print("Timezone set for this session to: " + tz.getDisplayName( + TextStyle.FULL, Locale.ENGLISH + )); + player.print("The current time in that timezone is: " + dateFormat.format(ZonedDateTime.now(tz))); + } catch (ZoneRulesException e) { + player.printError("Invalid timezone"); + } } @Command( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java index 349089e50..dcb06b4f9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java @@ -29,17 +29,19 @@ import com.sk89q.worldedit.util.command.composition.CommandExecutor; import java.util.Collections; import java.util.List; +import javax.annotation.Nullable; + public class NumberParser implements CommandExecutor { private final String name; private final String description; - private final String defaultSuggestion; + private final @Nullable String defaultSuggestion; public NumberParser(String name, String description) { this(name, description, null); } - public NumberParser(String name, String description, String defaultSuggestion) { + public NumberParser(String name, String description, @Nullable String defaultSuggestion) { this.name = name; this.description = description; this.defaultSuggestion = defaultSuggestion; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java new file mode 100644 index 000000000..5e9d2ed66 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java @@ -0,0 +1,98 @@ +/* + * 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.command.argument; + +import com.sk89q.worldedit.registry.Registry; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.fluid.FluidCategory; +import com.sk89q.worldedit.world.fluid.FluidType; +import com.sk89q.worldedit.world.gamemode.GameMode; +import com.sk89q.worldedit.world.item.ItemCategory; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.weather.WeatherType; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import java.util.stream.Collectors; + +public class RegistryConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(BlockType.class), + new RegistryConverter<>(BlockType.class, BlockType.REGISTRY)); + commandManager.registerConverter(Key.of(BlockCategory.class), + new RegistryConverter<>(BlockCategory.class, BlockCategory.REGISTRY)); + commandManager.registerConverter(Key.of(ItemType.class), + new RegistryConverter<>(ItemType.class, ItemType.REGISTRY)); + commandManager.registerConverter(Key.of(ItemCategory.class), + new RegistryConverter<>(ItemCategory.class, ItemCategory.REGISTRY)); + commandManager.registerConverter(Key.of(BiomeType.class), + new RegistryConverter<>(BiomeType.class, BiomeType.REGISTRY)); + commandManager.registerConverter(Key.of(EntityType.class), + new RegistryConverter<>(EntityType.class, EntityType.REGISTRY)); + commandManager.registerConverter(Key.of(FluidType.class), + new RegistryConverter<>(FluidType.class, FluidType.REGISTRY)); + commandManager.registerConverter(Key.of(FluidCategory.class), + new RegistryConverter<>(FluidCategory.class, FluidCategory.REGISTRY)); + commandManager.registerConverter(Key.of(GameMode.class), + new RegistryConverter<>(GameMode.class, GameMode.REGISTRY)); + commandManager.registerConverter(Key.of(WeatherType.class), + new RegistryConverter<>(WeatherType.class, WeatherType.REGISTRY)); + } + + private final Registry registry; + private final TextComponent choices; + + public RegistryConverter(Class clazz, Registry registry) { + this.registry = registry; + this.choices = TextComponent.of("any " + clazz.getSimpleName()); + } + + @Override + public Component describeAcceptableArguments() { + return this.choices; + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess injectedValueAccess) { + V result = registry.get(argument); + return result == null + ? FailedConversion.from(new IllegalArgumentException("Not a valid choice: " + argument)) + : SuccessfulConversion.fromSingle(result); + } + + @Override + public List getSuggestions(String input) { + return registry.keySet().stream() + .filter(string -> string.startsWith(input)) + .collect(Collectors.toList()); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringParser.java index 298f999e4..30c02381f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringParser.java @@ -29,17 +29,19 @@ import com.sk89q.worldedit.util.command.composition.CommandExecutor; import java.util.Collections; import java.util.List; +import javax.annotation.Nullable; + public class StringParser implements CommandExecutor { private final String name; private final String description; - private final String defaultSuggestion; + private final @Nullable String defaultSuggestion; public StringParser(String name, String description) { this(name, description, null); } - public StringParser(String name, String description, String defaultSuggestion) { + public StringParser(String name, String description, @Nullable String defaultSuggestion) { this.name = name; this.description = description; this.defaultSuggestion = defaultSuggestion; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index b8e5f2101..c8f363a11 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -75,6 +75,7 @@ import com.sk89q.worldedit.command.argument.EnumConverter; import com.sk89q.worldedit.command.argument.ExpandAmountConverter; import com.sk89q.worldedit.command.argument.FactoryConverter; import com.sk89q.worldedit.command.argument.RegionFactoryConverter; +import com.sk89q.worldedit.command.argument.RegistryConverter; import com.sk89q.worldedit.command.argument.VectorConverter; import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter; import com.sk89q.worldedit.command.util.PermissionCondition; @@ -196,6 +197,7 @@ public final class PlatformCommandManager { } VectorConverter.register(commandManager); EnumConverter.register(commandManager); + RegistryConverter.register(commandManager); ExpandAmountConverter.register(commandManager); ZonedDateTimeConverter.register(commandManager); BooleanConverter.register(commandManager); From 7dcf8f5a457715d9d9819d795c02503c457b8b8d Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 27 Apr 2019 17:32:02 +1000 Subject: [PATCH 077/366] Fixed //setbiome --- .../main/java/com/sk89q/worldedit/command/BiomeCommands.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index 0bf6878dd..f6aad8a0d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -178,7 +178,7 @@ public class BiomeCommands { @Logging(REGION) @CommandPermissions("worldedit.biome.set") public void setBiome(Player player, LocalSession session, EditSession editSession, - BiomeType target, + @Arg(desc = "Biome type.") BiomeType target, @Switch(name = 'p', desc = "Use your current position") boolean atPosition) throws WorldEditException { World world = player.getWorld(); From 0960f70e6b50d875df82415d094d5c5ffc4d4be0 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 27 Apr 2019 03:33:13 -0700 Subject: [PATCH 078/366] Update to latest Piston changes --- .../worldedit/command/SchematicCommands.java | 8 ++- .../command/util/PrintCommandHelp.java | 14 +++-- .../platform/PlatformCommandManager.java | 28 +++++++--- .../command/WorldEditExceptionConverter.java | 56 ++++++++++--------- .../formatting/component/CommandUsageBox.java | 26 +++++---- 5 files changed, 77 insertions(+), 55 deletions(-) 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 5fd4c6d98..c06fe851f 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 @@ -39,6 +39,7 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.io.file.FilenameException; import org.enginehub.piston.annotation.Command; @@ -159,7 +160,7 @@ public class SchematicCommands { boolean overwrite = f.exists(); if (overwrite) { if (!player.hasPermission("worldedit.schematic.delete")) { - throw new StopExecutionException("That schematic already exists!"); + throw new StopExecutionException(TextComponent.of("That schematic already exists!")); } if (!allowOverwrite) { player.printError("That schematic already exists. Use the -f flag to overwrite it."); @@ -186,7 +187,8 @@ public class SchematicCommands { File parent = f.getParentFile(); if (parent != null && !parent.exists()) { if (!parent.mkdirs()) { - throw new StopExecutionException("Could not create folder for schematics!"); + throw new StopExecutionException(TextComponent.of( + "Could not create folder for schematics!")); } } @@ -277,7 +279,7 @@ public class SchematicCommands { @Switch(name = 'n', desc = "Sort by date, newest first") boolean newFirst) { if (oldFirst && newFirst) { - throw new StopExecutionException("Cannot sort by oldest and newest."); + throw new StopExecutionException(TextComponent.of("Cannot sort by oldest and newest.")); } File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir); List fileList = allFiles(dir); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java index b1971b0a9..b59578a49 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -83,13 +83,13 @@ public class PrintCommandHelp { return; } - List visited = new ArrayList<>(); + List visited = new ArrayList<>(); Command currentCommand = detectCommand(manager, commandPath.get(0)); if (currentCommand == null) { actor.printError(String.format("The command '%s' could not be found.", commandPath.get(0))); return; } - visited.add(commandPath.get(0)); + visited.add(currentCommand); // Drill down to the command for (int i = 1; i < commandPath.size(); i++) { @@ -103,8 +103,8 @@ public class PrintCommandHelp { } if (subCommands.containsKey(subCommand)) { - visited.add(subCommand); currentCommand = subCommands.get(subCommand); + visited.add(currentCommand); } else { actor.printError(String.format("The sub-command '%s' under '%s' could not be found.", subCommand, Joiner.on(" ").join(visited))); @@ -116,7 +116,8 @@ public class PrintCommandHelp { if (subCommands.isEmpty()) { // Create the message - CommandUsageBox box = new CommandUsageBox(currentCommand, String.join(" ", visited)); + CommandUsageBox box = new CommandUsageBox(visited, visited.stream() + .map(Command::getName).collect(Collectors.joining(" "))); actor.print(box.create()); } else { printAllCommands(page, perPage, subCommands.values().stream(), actor, visited); @@ -124,7 +125,7 @@ public class PrintCommandHelp { } private static void printAllCommands(int page, int perPage, Stream commandStream, Actor actor, - List commandList) { + List commandList) { // Get a list of aliases List commands = commandStream .sorted(byCleanName()) @@ -151,7 +152,8 @@ public class PrintCommandHelp { // Add each command for (Command mapping : list) { String alias = (commandList.isEmpty() ? "/" : "") + mapping.getName(); - String command = Stream.concat(commandList.stream(), Stream.of(mapping.getName())) + String command = Stream.concat(commandList.stream(), Stream.of(mapping)) + .map(Command::getName) .collect(Collectors.joining(" ", "/", "")); box.appendCommand(alias, mapping.getDescription(), command); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index c8f363a11..93ba549dd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -94,9 +94,11 @@ import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; import com.sk89q.worldedit.world.World; +import org.enginehub.piston.ColorConfig; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; import org.enginehub.piston.DefaultCommandManagerService; @@ -112,6 +114,7 @@ import org.enginehub.piston.inject.MapBackedValueStore; import org.enginehub.piston.inject.MemoizingValueAccess; import org.enginehub.piston.inject.MergedValueAccess; import org.enginehub.piston.part.SubCommandPart; +import org.enginehub.piston.util.HelpGenerator; import org.enginehub.piston.util.ValueProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -499,21 +502,28 @@ public final class PlatformCommandManager { actor.printError("You are not permitted to do that. Are you in the right mode?"); } } catch (UsageException e) { - String message = e.getMessage(); - actor.printError(message != null ? message : "The command was not used properly (no more help available)."); + actor.print(TextComponent.builder("") + .color(TextColor.RED) + .append(e.getRichMessage()) + .build()); + ImmutableList cmd = e.getCommands(); + if (cmd.size() > 0) { + actor.print(TextComponent.builder("Usage: ") + .color(TextColor.RED) + .append(TextComponent.of("/", ColorConfig.getMainText())) + .append(HelpGenerator.create(cmd).getUsage()) + .build()); + } } catch (CommandExecutionException e) { Throwable t = e.getCause(); actor.printError("Please report this error: [See console]"); actor.printRaw(t.getClass().getName() + ": " + t.getMessage()); log.error("An unexpected error while handling a WorldEdit command", t); } catch (CommandException e) { - String message = e.getMessage(); - if (message != null) { - actor.printError(e.getMessage()); - } else { - actor.printError("An unknown error has occurred! Please see console."); - log.error("An unknown error occurred", e); - } + actor.print(TextComponent.builder("") + .color(TextColor.RED) + .append(e.getRichMessage()) + .build()); } finally { Optional editSessionOpt = context.snapshotMemory().injectedValue(Key.of(EditSession.class)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java index b75d1c5b3..a11294527 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.internal.command; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.DisallowedItemException; import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.IncompleteRegionException; @@ -39,6 +40,7 @@ import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.util.command.parametric.ExceptionConverterHelper; import com.sk89q.worldedit.util.command.parametric.ExceptionMatch; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException; import com.sk89q.worldedit.util.io.file.FilenameResolutionException; import com.sk89q.worldedit.util.io.file.InvalidFilenameException; @@ -61,110 +63,114 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { this.worldEdit = worldEdit; } + private CommandException newCommandException(String message, Throwable cause) { + return new CommandException(TextComponent.of(message), cause, ImmutableList.of()); + } + @ExceptionMatch public void convert(NumberFormatException e) throws CommandException { final Matcher matcher = numberFormat.matcher(e.getMessage()); if (matcher.matches()) { - throw new CommandException("Number expected; string \"" + matcher.group(1) - + "\" given.", e, null); + throw newCommandException("Number expected; string \"" + matcher.group(1) + + "\" given.", e); } else { - throw new CommandException("Number expected; string given.", e, null); + throw newCommandException("Number expected; string given.", e); } } @ExceptionMatch public void convert(IncompleteRegionException e) throws CommandException { - throw new CommandException("Make a region selection first.", e, null); + throw newCommandException("Make a region selection first.", e); } @ExceptionMatch public void convert(UnknownItemException e) throws CommandException { - throw new CommandException("Block name '" + e.getID() + "' was not recognized.", e, null); + throw newCommandException("Block name '" + e.getID() + "' was not recognized.", e); } @ExceptionMatch public void convert(InvalidItemException e) throws CommandException { - throw new CommandException(e.getMessage(), e, null); + throw newCommandException(e.getMessage(), e); } @ExceptionMatch public void convert(DisallowedItemException e) throws CommandException { - throw new CommandException("Block '" + e.getID() - + "' not allowed (see WorldEdit configuration).", e, null); + throw newCommandException("Block '" + e.getID() + + "' not allowed (see WorldEdit configuration).", e); } @ExceptionMatch public void convert(MaxChangedBlocksException e) throws CommandException { - throw new CommandException("Max blocks changed in an operation reached (" - + e.getBlockLimit() + ").", e, null); + throw newCommandException("Max blocks changed in an operation reached (" + + e.getBlockLimit() + ").", e); } @ExceptionMatch public void convert(MaxBrushRadiusException e) throws CommandException { - throw new CommandException("Maximum brush radius (in configuration): " + worldEdit.getConfiguration().maxBrushRadius, e, null); + throw newCommandException("Maximum brush radius (in configuration): " + worldEdit.getConfiguration().maxBrushRadius, e); } @ExceptionMatch public void convert(MaxRadiusException e) throws CommandException { - throw new CommandException("Maximum radius (in configuration): " + worldEdit.getConfiguration().maxRadius, e, null); + throw newCommandException("Maximum radius (in configuration): " + worldEdit.getConfiguration().maxRadius, e); } @ExceptionMatch public void convert(UnknownDirectionException e) throws CommandException { - throw new CommandException("Unknown direction: " + e.getDirection(), e, null); + throw newCommandException("Unknown direction: " + e.getDirection(), e); } @ExceptionMatch public void convert(InsufficientArgumentsException e) throws CommandException { - throw new CommandException(e.getMessage(), e, null); + throw newCommandException(e.getMessage(), e); } @ExceptionMatch public void convert(RegionOperationException e) throws CommandException { - throw new CommandException(e.getMessage(), e, null); + throw newCommandException(e.getMessage(), e); } @ExceptionMatch public void convert(ExpressionException e) throws CommandException { - throw new CommandException(e.getMessage(), e, null); + throw newCommandException(e.getMessage(), e); } @ExceptionMatch public void convert(EmptyClipboardException e) throws CommandException { - throw new CommandException("Your clipboard is empty. Use //copy first.", e, null); + throw newCommandException("Your clipboard is empty. Use //copy first.", e); } @ExceptionMatch public void convert(InvalidFilenameException e) throws CommandException { - throw new CommandException("Filename '" + e.getFilename() + "' invalid: " - + e.getMessage(), e, null); + throw newCommandException("Filename '" + e.getFilename() + "' invalid: " + + e.getMessage(), e); } @ExceptionMatch public void convert(FilenameResolutionException e) throws CommandException { - throw new CommandException( - "File '" + e.getFilename() + "' resolution error: " + e.getMessage(), e, null); + throw newCommandException( + "File '" + e.getFilename() + "' resolution error: " + e.getMessage(), e); } @ExceptionMatch public void convert(InvalidToolBindException e) throws CommandException { - throw new CommandException("Can't bind tool to " + e.getItemType().getName() + ": " + e.getMessage(), e, null); + throw newCommandException("Can't bind tool to " + e.getItemType().getName() + ": " + e.getMessage(), e); } @ExceptionMatch public void convert(FileSelectionAbortedException e) throws CommandException { - throw new CommandException("File selection aborted.", e, null); + throw newCommandException("File selection aborted.", e); } @ExceptionMatch public void convert(WorldEditException e) throws CommandException { - throw new CommandException(e.getMessage(), e, null); + throw newCommandException(e.getMessage(), e); } @ExceptionMatch public void convert(IllegalArgumentException e) throws CommandException { - throw new CommandException(e.getMessage(), e, null); + throw newCommandException(e.getMessage(), e); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index 69d5339f7..6b6314b73 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -19,8 +19,10 @@ package com.sk89q.worldedit.util.formatting.component; +import com.google.common.collect.Iterables; import org.enginehub.piston.Command; import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.util.HelpGenerator; import javax.annotation.Nullable; import java.util.List; @@ -39,26 +41,26 @@ public class CommandUsageBox extends TextComponentProducer { /** * Create a new usage box. * - * @param command the command to describe - * @param commandString the command that was used, such as "/we" or "/brush sphere" + * @param commands the commands to describe + * @param commandString the commands that were used, such as "/we" or "/brush sphere" */ - public CommandUsageBox(Command command, String commandString) { - this(command, commandString, null); + public CommandUsageBox(List commands, String commandString) { + this(commands, commandString, null); } /** * Create a new usage box. * - * @param command the command to describe - * @param commandString the command that was used, such as "/we" or "/brush sphere" + * @param commands the commands to describe + * @param commandString the commands that were used, such as "/we" or "/brush sphere" * @param parameters list of parameters to use */ - public CommandUsageBox(Command command, String commandString, @Nullable CommandParameters parameters) { - checkNotNull(command); + public CommandUsageBox(List commands, String commandString, @Nullable CommandParameters parameters) { + checkNotNull(commands); checkNotNull(commandString); - Map subCommands = getSubCommands(command); + Map subCommands = getSubCommands(Iterables.getLast(commands)); if (subCommands.isEmpty()) { - attachCommandUsage(command, commandString); + attachCommandUsage(commands, commandString); } else { attachSubcommandUsage(subCommands, commandString, parameters); } @@ -81,9 +83,9 @@ public class CommandUsageBox extends TextComponentProducer { append(box.create()); } - private void attachCommandUsage(Command description, String commandString) { + private void attachCommandUsage(List commands, String commandString) { MessageBox box = new MessageBox("Help for " + commandString, - new TextComponentProducer().append(description.getFullHelp())); + new TextComponentProducer().append(HelpGenerator.create(commands).getFullHelp())); append(box.create()); } From 62353a46db6e04e85ebe80700477291775790bbd Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 27 Apr 2019 21:57:25 +1000 Subject: [PATCH 079/366] Added a pagination box and use it in Biome List and Chunk List --- .../worldedit/bukkit/BukkitCommandSender.java | 4 +- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 3 +- .../worldedit/command/BiomeCommands.java | 44 ++----- .../worldedit/command/ChunkCommands.java | 13 +- .../worldedit/extension/platform/Actor.java | 5 +- .../extension/platform/PlayerProxy.java | 4 +- .../component/InvalidComponentException.java | 29 +++++ .../util/formatting/component/MessageBox.java | 2 +- .../formatting/component/PaginationBox.java | 119 ++++++++++++++++++ .../component/TextComponentProducer.java | 15 +++ .../sk89q/worldedit/forge/ForgePlayer.java | 4 +- .../worldedit/sponge/SpongeCommandSender.java | 4 +- .../sk89q/worldedit/sponge/SpongePlayer.java | 7 +- 13 files changed, 201 insertions(+), 52 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/InvalidComponentException.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java index b82dfe458..2d4ea70cf 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java @@ -26,7 +26,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.auth.AuthorizationException; -import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -94,7 +94,7 @@ public class BukkitCommandSender implements Actor { } @Override - public void print(TextComponent component) { + public void print(Component component) { TextAdapter.sendComponent(sender, component); } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 71941a69d..12d7551de 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -127,7 +128,7 @@ public class BukkitPlayer extends AbstractPlayerActor { } @Override - public void print(TextComponent component) { + public void print(Component component) { TextAdapter.sendComponent(player, component); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index f6aad8a0d..b751dfefe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.command; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; + import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -42,6 +44,8 @@ import com.sk89q.worldedit.regions.FlatRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Regions; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeData; import com.sk89q.worldedit.world.biome.BiomeType; @@ -51,11 +55,10 @@ import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Switch; -import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; - -import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; +import java.util.stream.Collectors; /** * Implements biome-related commands such as "/biomelist". @@ -76,38 +79,15 @@ public class BiomeCommands { ) @CommandPermissions("worldedit.biome.list") public void biomeList(Player player, - @Arg(desc = "Page number.", def = "0") + @Arg(desc = "Page number.", def = "1") int page) throws WorldEditException { - int offset; - int count = 0; - - if (page < 2) { - page = 1; - offset = 0; - } else { - offset = (page - 1) * 19; - } - BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); - Collection biomes = BiomeType.REGISTRY.values(); - int totalPages = biomes.size() / 19 + 1; - player.print("Available Biomes (page " + page + "/" + totalPages + ") :"); - for (BiomeType biome : biomes) { - if (offset > 0) { - offset--; - } else { - BiomeData data = biomeRegistry.getData(biome); - if (data != null) { - player.print(" " + data.getName()); - if (++count == 19) { - break; - } - } else { - player.print(" "); - } - } - } + List biomes = BiomeType.REGISTRY.values().stream().map(biomeRegistry::getData).collect(Collectors.toList()); + + PaginationBox paginationBox = new PaginationBox("Available Biomes", "/biomelist %page%"); + paginationBox.setComponents(biomes.stream().map(biome -> TextComponent.of(biome.getName())).collect(Collectors.toList())); + player.print(paginationBox.create(page)); } @Command( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index 8f9dc6ceb..5dcce1699 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -33,15 +33,19 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.MathUtils; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.storage.LegacyChunkStore; import com.sk89q.worldedit.world.storage.McRegionChunkStore; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Set; +import java.util.stream.Collectors; /** * Commands for working with chunks. @@ -82,12 +86,13 @@ public class ChunkCommands { desc = "List chunks that your selection includes" ) @CommandPermissions("worldedit.listchunks") - public void listChunks(Player player, LocalSession session) throws WorldEditException { + public void listChunks(Player player, LocalSession session, + @Arg(desc = "Page number.", def = "1") int page) throws WorldEditException { Set chunks = session.getSelection(player.getWorld()).getChunks(); - for (BlockVector2 chunk : chunks) { - player.print(LegacyChunkStore.getFilename(chunk)); - } + PaginationBox paginationBox = new PaginationBox("Selected Chunks", "/listchunks %page%"); + paginationBox.setComponents(chunks.stream().map(chunk -> TextComponent.of(chunk.toString())).collect(Collectors.toList())); + player.print(paginationBox.create(page)); } @Command( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java index 45160de66..319c9cb02 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionOwner; import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.auth.Subject; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import java.io.File; @@ -77,11 +78,11 @@ public interface Actor extends Identifiable, SessionOwner, Subject { void printError(String msg); /** - * Print a {@link TextComponent}. + * Print a {@link Component}. * * @param component The component to print */ - void print(TextComponent component); + void print(Component component); /** * Returns true if the actor can destroy bedrock. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java index 2159a2fce..8ecf3cc10 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java @@ -31,10 +31,10 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.gamemode.GameMode; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import java.util.UUID; @@ -134,7 +134,7 @@ class PlayerProxy extends AbstractPlayerActor { } @Override - public void print(TextComponent component) { + public void print(Component component) { basePlayer.print(component); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/InvalidComponentException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/InvalidComponentException.java new file mode 100644 index 000000000..bcdfb7f10 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/InvalidComponentException.java @@ -0,0 +1,29 @@ +/* + * 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.util.formatting.component; + +import com.sk89q.worldedit.WorldEditException; + +public class InvalidComponentException extends WorldEditException { + + public InvalidComponentException(String message) { + super(message); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java index 6828589bc..549943541 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java @@ -32,7 +32,7 @@ public class MessageBox extends TextComponentProducer { private static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 47; - private final TextComponentProducer contents; + private TextComponentProducer contents; /** * Create a new box. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java new file mode 100644 index 000000000..fecdac40c --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java @@ -0,0 +1,119 @@ +/* + * 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.util.formatting.component; + +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; + +import java.util.List; + +public class PaginationBox extends MessageBox { + + public static final int IDEAL_ROWS_FOR_PLAYER = 8; + + private String pageCommand; + private List components; + private int componentsPerPage = IDEAL_ROWS_FOR_PLAYER; + + /** + * Creates a Paginated component + * + * @param title The title + */ + public PaginationBox(String title) { + this(title, null); + } + + /** + * Sets the components to create pages for. + * + * @param components The components + */ + public void setComponents(List components) { + this.components = components; + } + + public void setComponentsPerPage(int componentsPerPage) { + this.componentsPerPage = componentsPerPage; + } + + /** + * Creates a Paginated component + * + * @param title The title + * @param pageCommand The command to run to switch page, with %page% representing page number + */ + public PaginationBox(String title, String pageCommand) { + super(title, new TextComponentProducer()); + + if (pageCommand != null && !pageCommand.contains("%page%")) { + throw new IllegalArgumentException("pageCommand must contain %page% if provided."); + } + this.pageCommand = pageCommand; + } + + public TextComponent create(int page) throws InvalidComponentException { + if (components == null) { + throw new IllegalStateException("You must provide components before creating."); + } + if (page == 1 && components.isEmpty()) { + return getContents().reset().append("There's nothing to see here").create(); + } + int pageCount = (int) Math.ceil(components.size() / (double) componentsPerPage); + if (page < 1 || page > pageCount) { + throw new InvalidComponentException("Invalid page number."); + } + getContents().reset(); + for (int i = (page - 1) * componentsPerPage; i < Math.min(page * componentsPerPage, components.size()); i++) { + getContents().append(components.get(i)).newline(); + } + TextComponent pageNumberComponent = TextComponent.of("Page ", TextColor.YELLOW) + .append(TextComponent.of(String.valueOf(page), TextColor.GOLD)) + .append(TextComponent.of(" of ")) + .append(TextComponent.of(String.valueOf(pageCount), TextColor.GOLD)); + + if (pageCommand != null) { + if (page > 1) { + TextComponent prevComponent = TextComponent.of("<<< ", TextColor.GOLD) + .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page - 1)))) + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate"))); + getContents().append(prevComponent); + } + getContents().append(pageNumberComponent); + if (page < pageCount) { + TextComponent nextComponent = TextComponent.of(" >>>", TextColor.GOLD) + .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page + 1)))) + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate"))); + getContents().append(nextComponent); + } + } else { + getContents().append(pageNumberComponent); + } + return TextComponent.of("").append(Component.newline()).append(super.create()); + } + + @Override + public TextComponent create() { + throw new IllegalStateException("Pagination components must be created with a page"); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java index 32a9f8d30..fed34ea23 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java @@ -62,7 +62,22 @@ public class TextComponentProducer { return this; } + /** + * Create a TextComponent from this producer. + * + * @return The component + */ public TextComponent create() { return builder.build(); } + + /** + * Reset the producer to a clean slate. + * + * @return The producer, for chaining + */ + public TextComponentProducer reset() { + builder = TextComponent.builder().content(""); + return this; + } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index edc5275ab..c478934c5 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -31,7 +31,7 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -143,7 +143,7 @@ public class ForgePlayer extends AbstractPlayerActor { } @Override - public void print(TextComponent component) { + public void print(Component component) { this.player.sendMessage(ITextComponent.Serializer.fromJson(GsonComponentSerializer.INSTANCE.serialize(component))); } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java index e44146b3c..e6eac1f83 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java @@ -26,7 +26,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.auth.AuthorizationException; -import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.adapter.spongeapi.TextAdapter; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.entity.living.player.Player; @@ -92,7 +92,7 @@ public class SpongeCommandSender implements Actor { } @Override - public void print(TextComponent component) { + public void print(Component component) { TextAdapter.sendComponent(sender, component); } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java index 099780b3d..82723fe93 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java @@ -31,13 +31,12 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.adapter.spongeapi.TextAdapter; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemTypes; - -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.adapter.spongeapi.TextAdapter; import org.spongepowered.api.Sponge; import org.spongepowered.api.data.type.HandTypes; import org.spongepowered.api.entity.living.player.Player; @@ -152,7 +151,7 @@ public class SpongePlayer extends AbstractPlayerActor { } @Override - public void print(TextComponent component) { + public void print(Component component) { TextAdapter.sendComponent(player, component); } From 484a1db500c18b747963cba6a222f52c6d593225 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 27 Apr 2019 13:37:43 -0700 Subject: [PATCH 080/366] Remove artifactory resolve block --- build.gradle | 9 --------- 1 file changed, 9 deletions(-) diff --git a/build.gradle b/build.gradle index 41de17bb8..8bdc30616 100644 --- a/build.gradle +++ b/build.gradle @@ -69,15 +69,6 @@ artifactory { ivy = false } } - - resolve { - repository { - repoKey = 'repo' - username = "${artifactory_user}" - password = "${artifactory_password}" - maven = true - } - } } artifactoryPublish.skip = true From b3053f19ce07be2b5eb7b12cf59feb51574f8ae2 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 28 Apr 2019 01:12:05 -0400 Subject: [PATCH 081/366] Pagination changes and cleanup. Refactored PaginationBox to be abstract. Implementations can generate individual components as needed now. Add lots of Component usage to schematic list, help listings, etc. Fix a few schematic and file resolution issues. --- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 1 - .../bukkit/BukkitServerInterface.java | 2 +- .../java/com/sk89q/worldedit/WorldEdit.java | 13 ++- .../worldedit/command/BiomeCommands.java | 12 +-- .../worldedit/command/ChunkCommands.java | 9 +- .../worldedit/command/SchematicCommands.java | 62 +++----------- .../worldedit/command/SelectionCommands.java | 4 +- .../worldedit/command/UtilityCommands.java | 23 ++++- .../command/util/PrintCommandHelp.java | 78 ++++++++--------- .../worldedit/extension/platform/Actor.java | 1 - .../platform/PlatformCommandManager.java | 23 +++-- .../clipboard/io/SpongeSchematicReader.java | 9 +- .../formatting/component/CommandListBox.java | 72 +++++++++++----- .../formatting/component/CommandUsageBox.java | 11 +-- .../util/formatting/component/MessageBox.java | 49 +++++++---- .../formatting/component/PaginationBox.java | 84 ++++++++++++------- .../component/SchematicPaginationBox.java | 56 +++++++++++++ 17 files changed, 307 insertions(+), 202 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 12d7551de..c0dc5c7e2 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -38,7 +38,6 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; import org.bukkit.Bukkit; import org.bukkit.Location; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 8461826f9..34ad4c257 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -72,7 +72,7 @@ public class BukkitServerInterface implements MultiUserPlatform { if (plugin.getBukkitImplAdapter() != null) { return plugin.getBukkitImplAdapter().getDataVersion(); } - return 0; + return -1; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index e206f383f..205cfde5f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -303,6 +303,17 @@ public final class WorldEdit { if (exts.size() != 1) { exts = exts.subList(0, 1); } + } else { + int dot = filename.lastIndexOf('.'); + if (dot < 0 || dot == filename.length() - 1) { + String currentExt = filename.substring(dot + 1); + if (exts.contains(currentExt) && checkFilename(filename)) { + File f = new File(dir, filename); + if (f.exists()) { + return f; + } + } + } } File result = null; for (Iterator iter = exts.iterator(); iter.hasNext() && (result == null || (!isSave && !result.exists()));) { @@ -317,7 +328,7 @@ public final class WorldEdit { private File getSafeFileWithExtension(File dir, String filename, String extension) { if (extension != null) { int dot = filename.lastIndexOf('.'); - if (dot < 0 || !filename.substring(dot).equalsIgnoreCase(extension)) { + if (dot < 0 || dot == filename.length() - 1 || !filename.substring(dot + 1).equalsIgnoreCase(extension)) { filename += "." + extension; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index b751dfefe..bb4788f9e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -45,7 +45,6 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Regions; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.component.PaginationBox; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeData; import com.sk89q.worldedit.world.biome.BiomeType; @@ -56,7 +55,7 @@ import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Switch; import java.util.HashSet; -import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -83,10 +82,11 @@ public class BiomeCommands { int page) throws WorldEditException { BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); - List biomes = BiomeType.REGISTRY.values().stream().map(biomeRegistry::getData).collect(Collectors.toList()); - PaginationBox paginationBox = new PaginationBox("Available Biomes", "/biomelist %page%"); - paginationBox.setComponents(biomes.stream().map(biome -> TextComponent.of(biome.getName())).collect(Collectors.toList())); + PaginationBox paginationBox = PaginationBox.fromStrings("Available Biomes", "/biomelist %page%", + BiomeType.REGISTRY.values().stream() + .map(biomeRegistry::getData).filter(Objects::nonNull) + .map(BiomeData::getName).collect(Collectors.toList())); player.print(paginationBox.create(page)); } @@ -152,7 +152,7 @@ public class BiomeCommands { @Command( name = "/setbiome", - desc = "Sets the biome of the player's current block or region.", + desc = "Sets the biome of your current block or region.", descFooter = "By default, uses all the blocks in your selection" ) @Logging(REGION) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index 5dcce1699..8dc99dc15 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -34,7 +34,6 @@ import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.MathUtils; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.component.PaginationBox; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.storage.LegacyChunkStore; import com.sk89q.worldedit.world.storage.McRegionChunkStore; import org.enginehub.piston.annotation.Command; @@ -62,10 +61,10 @@ public class ChunkCommands { @Command( name = "chunkinfo", - desc = "Get information about the chunk that you are inside" + desc = "Get information about the chunk you're inside" ) @CommandPermissions("worldedit.chunkinfo") - public void chunkInfo(Player player) throws WorldEditException { + public void chunkInfo(Player player) { Location pos = player.getBlockIn(); int chunkX = (int) Math.floor(pos.getBlockX() / 16.0); int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0); @@ -90,8 +89,8 @@ public class ChunkCommands { @Arg(desc = "Page number.", def = "1") int page) throws WorldEditException { Set chunks = session.getSelection(player.getWorld()).getChunks(); - PaginationBox paginationBox = new PaginationBox("Selected Chunks", "/listchunks %page%"); - paginationBox.setComponents(chunks.stream().map(chunk -> TextComponent.of(chunk.toString())).collect(Collectors.toList())); + PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks %page%", + chunks.stream().map(BlockVector2::toString).collect(Collectors.toList())); player.print(paginationBox.create(page)); } 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 c06fe851f..fe4f5f1de 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 @@ -19,8 +19,6 @@ package com.sk89q.worldedit.command; -import com.google.common.collect.Multimap; -import com.google.common.io.Files; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -39,6 +37,8 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.component.SchematicPaginationBox; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.io.file.FilenameException; @@ -60,7 +60,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.regex.Pattern; import static com.google.common.base.Preconditions.checkNotNull; @@ -70,10 +69,6 @@ import static com.google.common.base.Preconditions.checkNotNull; @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class SchematicCommands { - /** - * 9 schematics per page fits in the MC chat window. - */ - private static final int SCHEMATICS_PER_PAGE = 9; private static final Logger log = LoggerFactory.getLogger(SchematicCommands.class); private final WorldEdit worldEdit; @@ -100,7 +95,9 @@ public class SchematicCommands { LocalConfiguration config = worldEdit.getConfiguration(); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); - File f = worldEdit.getSafeOpenFile(player, dir, filename, BuiltInClipboardFormat.SPONGE_SCHEMATIC.getPrimaryFileExtension(), ClipboardFormats.getFileExtensionArray()); + File f = worldEdit.getSafeOpenFile(player, dir, filename, + BuiltInClipboardFormat.SPONGE_SCHEMATIC.getPrimaryFileExtension(), + ClipboardFormats.getFileExtensionArray()); if (!f.exists()) { player.printError("Schematic " + filename + " does not exist!"); @@ -128,7 +125,7 @@ public class SchematicCommands { player.print(filename + " loaded. Paste it with //paste"); } catch (IOException e) { player.printError("Schematic could not read or it does not exist: " + e.getMessage()); - log.warn("Failed to load a saved clipboard", e); + log.warn("Failed to load schematic: " + e.getMessage()); } } @@ -277,7 +274,7 @@ public class SchematicCommands { @Switch(name = 'd', desc = "Sort by date, oldest first") boolean oldFirst, @Switch(name = 'n', desc = "Sort by date, newest first") - boolean newFirst) { + boolean newFirst) throws WorldEditException { if (oldFirst && newFirst) { throw new StopExecutionException(TextComponent.of("Cannot sort by oldest and newest.")); } @@ -292,16 +289,6 @@ public class SchematicCommands { File[] files = new File[fileList.size()]; fileList.toArray(files); - int pageCount = files.length / SCHEMATICS_PER_PAGE + 1; - if (page < 1) { - actor.printError("Page must be at least 1"); - return; - } - if (page > pageCount) { - actor.printError("Page must be less than " + (pageCount + 1)); - return; - } - final int sortType = oldFirst ? -1 : newFirst ? 1 : 0; // cleanup file list Arrays.sort(files, (f1, f2) -> { @@ -321,20 +308,9 @@ public class SchematicCommands { return res; }); - List schematics = listFiles(worldEdit.getConfiguration().saveDir, files); - int offset = (page - 1) * SCHEMATICS_PER_PAGE; - - actor.print("Available schematics (Filename: Format) [" + page + "/" + pageCount + "]:"); - StringBuilder build = new StringBuilder(); - int limit = Math.min(offset + SCHEMATICS_PER_PAGE, schematics.size()); - for (int i = offset; i < limit; ) { - build.append(schematics.get(i)); - if (++i != limit) { - build.append("\n"); - } - } - - actor.print(build.toString()); + String pageCommand = actor.isPlayer() ? "/schem list -p %page%" + (oldFirst ? " -d" : newFirst ? " -n" : "") : null; + PaginationBox paginationBox = new SchematicPaginationBox(worldEdit.getConfiguration().saveDir, files, pageCommand); + actor.print(paginationBox.create(page)); } private List allFiles(File root) { @@ -353,22 +329,4 @@ public class SchematicCommands { return fileList; } - private List listFiles(String prefix, File[] files) { - if (prefix == null) prefix = ""; - List result = new ArrayList<>(); - for (File file : files) { - StringBuilder build = new StringBuilder(); - - build.append("\u00a72"); - //ClipboardFormat format = ClipboardFormats.findByFile(file); - Multimap exts = ClipboardFormats.getFileExtensionMap(); - ClipboardFormat format = exts.get(Files.getFileExtension(file.getName())) - .stream().findFirst().orElse(null); - boolean inRoot = file.getParentFile().getName().equals(prefix); - build.append(inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1]) - .append(": ").append(format == null ? "Unknown" : format.getName() + "*"); - result.add(build.toString()); - } - return result; - } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index c8674b085..d2e2a3708 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -624,7 +624,7 @@ public class SelectionCommands { } case UNKNOWN: default: - CommandListBox box = new CommandListBox("Selection modes"); + CommandListBox box = new CommandListBox("Selection modes", null); TextComponentProducer contents = box.getContents(); contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline(); @@ -636,7 +636,7 @@ public class SelectionCommands { box.appendCommand("cyl", "Select a cylinder", "//sel cyl"); box.appendCommand("convex", "Select a convex polyhedral", "//sel convex"); - player.print(box.create()); + player.print(box.create(1)); return; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index ea292a855..37facdddb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -51,6 +51,10 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CylinderRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.formatting.component.InvalidComponentException; +import com.sk89q.worldedit.util.formatting.component.SubtleFormat; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockTypes; import org.enginehub.piston.annotation.Command; @@ -58,8 +62,11 @@ import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Switch; +import java.text.DecimalFormat; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.function.Supplier; import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; @@ -474,6 +481,12 @@ public class UtilityCommands { return killed; } + // get the formatter with the system locale. in the future, if we can get a local from a player, we can use that + private static final DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.getDefault()); + static { + formatter.applyPattern("#,##0.#####"); // pattern is locale-insensitive. this can translate to "1.234,56789" + } + @Command( name = "/calculate", aliases = { "/calc", "/eval", "/evaluate", "/solve" }, @@ -485,8 +498,14 @@ public class UtilityCommands { String input) { try { Expression expression = Expression.compile(input); - actor.print("= " + expression.evaluate( - new double[] {}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout())); + double result = expression.evaluate( + new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout()); + String formatted = formatter.format(result); + actor.print(SubtleFormat.wrap(input + " = ") + .append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE))); + //actor.print(SubtleFormat.wrap(input).append(Component.newline()) + // .append(SubtleFormat.wrap("= ")) + // .append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE))); } catch (EvaluationException e) { actor.printError(String.format( "'%s' could not be evaluated (error: %s)", input, e.getMessage())); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java index b59578a49..df57539ba 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -22,13 +22,10 @@ package com.sk89q.worldedit.command.util; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.util.formatting.component.CodeFormat; import com.sk89q.worldedit.util.formatting.component.CommandListBox; import com.sk89q.worldedit.util.formatting.component.CommandUsageBox; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.component.InvalidComponentException; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; @@ -46,7 +43,7 @@ import static java.util.stream.Collectors.toList; /** * Implementation of the //help command. */ -// Stored in a separate class to prevent import conflicts. +// Stored in a separate class to prevent import conflicts, and because it's aliased via /we help. public class PrintCommandHelp { private static Command detectCommand(CommandManager manager, String command) { @@ -69,17 +66,11 @@ public class PrintCommandHelp { return mapping.orElse(null); } - public static void help(List commandPath, int page, WorldEdit we, Actor actor) { - if (page < 1) { - actor.printError("Page must be >= 1."); - return; - } + public static void help(List commandPath, int page, WorldEdit we, Actor actor) throws InvalidComponentException { CommandManager manager = we.getPlatformManager().getPlatformCommandManager().getCommandManager(); - final int perPage = actor instanceof Player ? 8 : 20; // More pages for console - if (commandPath.isEmpty()) { - printAllCommands(page, perPage, manager.getAllCommands(), actor, ImmutableList.of()); + printCommands(page, manager.getAllCommands(), actor, ImmutableList.of()); return; } @@ -98,7 +89,11 @@ public class PrintCommandHelp { if (subCommands.isEmpty()) { actor.printError(String.format("'%s' has no sub-commands. (Maybe '%s' is for a parameter?)", - Joiner.on(" ").join(visited), subCommand)); + Joiner.on(" ").join(visited.stream().map(Command::getName).iterator()), subCommand)); + // full help for single command + CommandUsageBox box = new CommandUsageBox(visited, visited.stream() + .map(Command::getName).collect(Collectors.joining(" "))); + actor.print(box.create()); return; } @@ -107,7 +102,11 @@ public class PrintCommandHelp { visited.add(currentCommand); } else { actor.printError(String.format("The sub-command '%s' under '%s' could not be found.", - subCommand, Joiner.on(" ").join(visited))); + subCommand, Joiner.on(" ").join(visited.stream().map(Command::getName).iterator()))); + // list subcommands for currentCommand + CommandUsageBox box = new CommandUsageBox(visited, visited.stream() + .map(Command::getName).collect(Collectors.joining(" "))); + actor.print(box.create()); return; } } @@ -120,46 +119,35 @@ public class PrintCommandHelp { .map(Command::getName).collect(Collectors.joining(" "))); actor.print(box.create()); } else { - printAllCommands(page, perPage, subCommands.values().stream(), actor, visited); + printCommands(page, subCommands.values().stream(), actor, visited); } } - private static void printAllCommands(int page, int perPage, Stream commandStream, Actor actor, - List commandList) { + private static void printCommands(int page, Stream commandStream, Actor actor, + List commandList) throws InvalidComponentException { // Get a list of aliases List commands = commandStream .sorted(byCleanName()) .collect(toList()); - // Calculate pagination - int offset = perPage * (page - 1); - int pageTotal = (int) Math.ceil(commands.size() / (double) perPage); - - // Box - CommandListBox box = new CommandListBox(String.format("Help: page %d/%d ", page, pageTotal)); - TextComponent.Builder tip = box.getContents().getBuilder().color(TextColor.GRAY); - - if (offset >= commands.size()) { - tip.color(TextColor.RED) - .append(TextComponent.of(String.format("There is no page %d (total number of pages is %d).\n", page, pageTotal))); - } else { - List list = commands.subList(offset, Math.min(offset + perPage, commands.size())); - - tip.append(TextComponent.of("Type ")); - tip.append(CodeFormat.wrap("//help [] ")); - tip.append(TextComponent.of(" for more information.\n")); - - // Add each command - for (Command mapping : list) { - String alias = (commandList.isEmpty() ? "/" : "") + mapping.getName(); - String command = Stream.concat(commandList.stream(), Stream.of(mapping)) - .map(Command::getName) - .collect(Collectors.joining(" ", "/", "")); - box.appendCommand(alias, mapping.getDescription(), command); - } + String used = commandList.isEmpty() ? null + : Joiner.on(" ").join(commandList.stream().map(Command::getName).iterator()); + CommandListBox box = new CommandListBox( + (used == null ? "Help" : "Subcommands: " + used), + "//help %page%" + (used == null ? "" : " " + used)); + if (!actor.isPlayer()) { + box.formatForConsole(); } - actor.print(box.create()); + for (Command mapping : commands) { + String alias = (commandList.isEmpty() ? "/" : "") + mapping.getName(); + String command = Stream.concat(commandList.stream(), Stream.of(mapping)) + .map(Command::getName) + .collect(Collectors.joining(" ", "/", "")); + box.appendCommand(alias, mapping.getDescription(), command); + } + + actor.print(box.create(page)); } private PrintCommandHelp() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java index 319c9cb02..cdcba32a2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Actor.java @@ -24,7 +24,6 @@ import com.sk89q.worldedit.session.SessionOwner; import com.sk89q.worldedit.util.Identifiable; import com.sk89q.worldedit.util.auth.Subject; import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import java.io.File; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 93ba549dd..34b5e0e82 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -94,6 +94,7 @@ import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; @@ -142,7 +143,6 @@ public final class PlatformCommandManager { private static final Logger log = LoggerFactory.getLogger(PlatformCommandManager.class); private static final java.util.logging.Logger COMMAND_LOG = java.util.logging.Logger.getLogger("com.sk89q.worldedit.CommandLog"); - private static final Pattern numberFormatExceptionPattern = Pattern.compile("^For input string: \"(.*)\"$"); private final WorldEdit worldEdit; private final PlatformManager platformManager; @@ -507,7 +507,7 @@ public final class PlatformCommandManager { .append(e.getRichMessage()) .build()); ImmutableList cmd = e.getCommands(); - if (cmd.size() > 0) { + if (!cmd.isEmpty()) { actor.print(TextComponent.builder("Usage: ") .color(TextColor.RED) .append(TextComponent.of("/", ColorConfig.getMainText())) @@ -515,15 +515,14 @@ public final class PlatformCommandManager { .build()); } } catch (CommandExecutionException e) { - Throwable t = e.getCause(); - actor.printError("Please report this error: [See console]"); - actor.printRaw(t.getClass().getName() + ": " + t.getMessage()); - log.error("An unexpected error while handling a WorldEdit command", t); + handleUnknownException(actor, e.getCause()); } catch (CommandException e) { actor.print(TextComponent.builder("") - .color(TextColor.RED) - .append(e.getRichMessage()) - .build()); + .color(TextColor.RED) + .append(e.getRichMessage()) + .build()); + } catch (Throwable t) { + handleUnknownException(actor, t); } finally { Optional editSessionOpt = context.snapshotMemory().injectedValue(Key.of(EditSession.class)); @@ -554,6 +553,12 @@ public final class PlatformCommandManager { event.setCancelled(true); } + private void handleUnknownException(Actor actor, Throwable t) { + actor.printError("Please report this error: [See console]"); + actor.printRaw(t.getClass().getName() + ": " + t.getMessage()); + log.error("An unexpected error while handling a WorldEdit command", t); + } + @Subscribe public void handleCommandSuggestion(CommandSuggestionEvent event) { try { 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 556a60570..4d33e82b7 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 @@ -102,10 +102,11 @@ public class SpongeSchematicReader extends NBTSchematicReader { return readVersion1(schematicTag); } else if (version == 2) { int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); - if (dataVersion > WorldEdit.getInstance().getPlatformManager() - .queryCapability(Capability.WORLD_EDITING).getDataVersion()) { - // maybe should just warn? simple schematics may be compatible still. - throw new IOException("Schematic was made in a newer Minecraft version. Data may be incompatible."); + int liveDataVersion = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.WORLD_EDITING).getDataVersion(); + if (dataVersion > liveDataVersion) { + log.warn("Schematic was made in a newer Minecraft version ({} > {}). Data may be incompatible.", + dataVersion, liveDataVersion); } BlockArrayClipboard clip = readVersion1(schematicTag); return readVersion2(clip, schematicTag); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java index f39a74656..4c08f6863 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -19,47 +19,75 @@ package com.sk89q.worldedit.util.formatting.component; +import com.google.common.collect.Lists; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; -public class CommandListBox extends MessageBox { +import java.util.List; - private boolean first = true; +public class CommandListBox extends PaginationBox { + + private List commands = Lists.newArrayList(); /** * Create a new box. * * @param title the title */ - public CommandListBox(String title) { - super(title, new TextComponentProducer()); + public CommandListBox(String title, String pageCommand) { + super(title, pageCommand); } - public CommandListBox appendCommand(String alias, Component description) { - return appendCommand(alias, description, null); + @Override + public Component getComponent(int number) { + return commands.get(number).createComponent(); } - public CommandListBox appendCommand(String alias, String description, String insertion) { - return appendCommand(alias, TextComponent.of(description), insertion); + @Override + public int getComponentsSize() { + return commands.size(); } - public CommandListBox appendCommand(String alias, Component description, String insertion) { - if (!first) { - getContents().newline(); + public void appendCommand(String alias, Component description) { + appendCommand(alias, description, null); + } + + public void appendCommand(String alias, String description, String insertion) { + appendCommand(alias, TextComponent.of(description), insertion); + } + + public void appendCommand(String alias, Component description, String insertion) { + commands.add(new CommandEntry(alias, description, insertion)); + } + + private static class CommandEntry { + private final String alias; + private final Component description; + private final String insertion; + + CommandEntry(String alias, Component description, String insertion) { + this.alias = alias; + this.description = description; + this.insertion = insertion; } - TextComponent commandName = TextComponent.of(alias, TextColor.GOLD); - if (insertion != null) { - commandName = commandName - .clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, insertion)) - .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select"))); - } - getContents().append(commandName.append(TextComponent.of(": "))); - getContents().append(description); - first = false; - return this; - } + Component createComponent() { + TextComponentProducer line = new TextComponentProducer(); + line.append(SubtleFormat.wrap("? ") + .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "//help " + insertion)) + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help")))); + TextComponent command = TextComponent.of(alias, TextColor.GOLD); + if (insertion == null) { + line.append(command); + } else { + line.append(command + .clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, insertion)) + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select")))); + } + return line.append(TextComponent.of(": ")).append(description).create(); + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index 6b6314b73..d2a97fcf2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -44,7 +44,7 @@ public class CommandUsageBox extends TextComponentProducer { * @param commands the commands to describe * @param commandString the commands that were used, such as "/we" or "/brush sphere" */ - public CommandUsageBox(List commands, String commandString) { + public CommandUsageBox(List commands, String commandString) throws InvalidComponentException { this(commands, commandString, null); } @@ -55,7 +55,7 @@ public class CommandUsageBox extends TextComponentProducer { * @param commandString the commands that were used, such as "/we" or "/brush sphere" * @param parameters list of parameters to use */ - public CommandUsageBox(List commands, String commandString, @Nullable CommandParameters parameters) { + public CommandUsageBox(List commands, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException { checkNotNull(commands); checkNotNull(commandString); Map subCommands = getSubCommands(Iterables.getLast(commands)); @@ -66,8 +66,9 @@ public class CommandUsageBox extends TextComponentProducer { } } - private void attachSubcommandUsage(Map dispatcher, String commandString, @Nullable CommandParameters parameters) { - CommandListBox box = new CommandListBox("Subcommands"); + private void attachSubcommandUsage(Map dispatcher, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException { + CommandListBox box = new CommandListBox(commandString.isEmpty() ? "Help" : "Subcommands:" + commandString, + "//help %page%" + (commandString.isEmpty() ? "" : " " + commandString)); String prefix = !commandString.isEmpty() ? commandString + " " : ""; List list = dispatcher.values().stream() @@ -80,7 +81,7 @@ public class CommandUsageBox extends TextComponentProducer { } } - append(box.create()); + append(box.create(1)); } private void attachCommandUsage(List commands, String commandString) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java index 549943541..1497ddbaa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java @@ -21,9 +21,12 @@ package com.sk89q.worldedit.util.formatting.component; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.base.Strings; +import com.google.common.collect.Sets; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.format.TextDecoration; /** * Makes for a box with a border above and below. @@ -40,28 +43,38 @@ public class MessageBox extends TextComponentProducer { public MessageBox(String title, TextComponentProducer contents) { checkNotNull(title); - int leftOver = GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH - title.length() - 2; - int leftSide = (int) Math.floor(leftOver * 1.0/3); - int rightSide = (int) Math.floor(leftOver * 2.0/3); - if (leftSide > 0) { - append(TextComponent.of(createBorder(leftSide), TextColor.YELLOW)); - } - append(Component.space()); - append(title); - append(Component.space()); - if (rightSide > 0) { - append(TextComponent.of(createBorder(rightSide), TextColor.YELLOW)); - } - newline(); + append(centerAndBorder(TextComponent.of(title))).newline(); this.contents = contents; } - private String createBorder(int count) { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < count; i++) { - builder.append("-"); + protected Component centerAndBorder(TextComponent text) { + TextComponentProducer line = new TextComponentProducer(); + int leftOver = GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH - getLength(text); + int side = (int) Math.floor(leftOver / 2.0); + if (side > 0) { + if (side > 1) { + line.append(createBorder(side - 1)); + } + line.append(Component.space()); } - return builder.toString(); + line.append(text); + if (side > 0) { + line.append(Component.space()); + if (side > 1) { + line.append(createBorder(side - 1)); + } + } + return line.create(); + } + + private static int getLength(TextComponent text) { + return text.content().length() + text.children().stream().filter(c -> c instanceof TextComponent) + .mapToInt(c -> getLength((TextComponent) c)).sum(); + } + + private TextComponent createBorder(int count) { + return TextComponent.of(Strings.repeat("-", count), + TextColor.YELLOW, Sets.newHashSet(TextDecoration.STRIKETHROUGH)); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java index fecdac40c..bba74a4db 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java @@ -25,14 +25,14 @@ import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import javax.annotation.Nullable; import java.util.List; -public class PaginationBox extends MessageBox { +public abstract class PaginationBox extends MessageBox { - public static final int IDEAL_ROWS_FOR_PLAYER = 8; + private static final int IDEAL_ROWS_FOR_PLAYER = 8; private String pageCommand; - private List components; private int componentsPerPage = IDEAL_ROWS_FOR_PLAYER; /** @@ -40,30 +40,30 @@ public class PaginationBox extends MessageBox { * * @param title The title */ - public PaginationBox(String title) { + protected PaginationBox(String title) { this(title, null); } - /** - * Sets the components to create pages for. - * - * @param components The components - */ - public void setComponents(List components) { - this.components = components; - } + public abstract Component getComponent(int number); + + public abstract int getComponentsSize(); public void setComponentsPerPage(int componentsPerPage) { this.componentsPerPage = componentsPerPage; } + public void formatForConsole() { + this.pageCommand = null; + this.componentsPerPage = 20; + } + /** * Creates a Paginated component * * @param title The title * @param pageCommand The command to run to switch page, with %page% representing page number */ - public PaginationBox(String title, String pageCommand) { + protected PaginationBox(String title, @Nullable String pageCommand) { super(title, new TextComponentProducer()); if (pageCommand != null && !pageCommand.contains("%page%")) { @@ -72,48 +72,76 @@ public class PaginationBox extends MessageBox { this.pageCommand = pageCommand; } - public TextComponent create(int page) throws InvalidComponentException { - if (components == null) { - throw new IllegalStateException("You must provide components before creating."); - } - if (page == 1 && components.isEmpty()) { + public Component create(int page) throws InvalidComponentException { + if (page == 1 && getComponentsSize() == 0) { return getContents().reset().append("There's nothing to see here").create(); } - int pageCount = (int) Math.ceil(components.size() / (double) componentsPerPage); + int pageCount = (int) Math.ceil(getComponentsSize() / (double) componentsPerPage); if (page < 1 || page > pageCount) { throw new InvalidComponentException("Invalid page number."); } - getContents().reset(); - for (int i = (page - 1) * componentsPerPage; i < Math.min(page * componentsPerPage, components.size()); i++) { - getContents().append(components.get(i)).newline(); + final int lastComp = Math.min(page * componentsPerPage, getComponentsSize()); + for (int i = (page - 1) * componentsPerPage; i < lastComp; i++) { + getContents().append(getComponent(i)); + if (i + 1 != lastComp) { + getContents().newline(); + } } + if (pageCount == 1) { + return super.create(); + } + getContents().newline(); TextComponent pageNumberComponent = TextComponent.of("Page ", TextColor.YELLOW) .append(TextComponent.of(String.valueOf(page), TextColor.GOLD)) .append(TextComponent.of(" of ")) .append(TextComponent.of(String.valueOf(pageCount), TextColor.GOLD)); - if (pageCommand != null) { + TextComponentProducer navProducer = new TextComponentProducer(); if (page > 1) { TextComponent prevComponent = TextComponent.of("<<< ", TextColor.GOLD) .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page - 1)))) .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate"))); - getContents().append(prevComponent); + navProducer.append(prevComponent); } - getContents().append(pageNumberComponent); + navProducer.append(pageNumberComponent); if (page < pageCount) { TextComponent nextComponent = TextComponent.of(" >>>", TextColor.GOLD) .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page + 1)))) .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate"))); - getContents().append(nextComponent); + navProducer.append(nextComponent); } + getContents().append(centerAndBorder(navProducer.create())); } else { - getContents().append(pageNumberComponent); + getContents().append(centerAndBorder(pageNumberComponent)); } - return TextComponent.of("").append(Component.newline()).append(super.create()); + return super.create(); } @Override public TextComponent create() { throw new IllegalStateException("Pagination components must be created with a page"); } + + public static PaginationBox fromStrings(String header, @Nullable String pageCommand, List lines) { + return new ListPaginationBox(header, pageCommand, lines); + } + + private static class ListPaginationBox extends PaginationBox { + private final List lines; + + ListPaginationBox(String header, String pageCommand, List lines) { + super(header, pageCommand); + this.lines = lines; + } + + @Override + public Component getComponent(int number) { + return TextComponent.of(lines.get(number)); + } + + @Override + public int getComponentsSize() { + return lines.size(); + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java new file mode 100644 index 000000000..6a1f0712c --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java @@ -0,0 +1,56 @@ +package com.sk89q.worldedit.util.formatting.component; + +import com.google.common.collect.Multimap; +import com.google.common.io.Files; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; + +import java.io.File; +import java.util.regex.Pattern; + +import static com.google.common.base.Preconditions.checkArgument; + +public class SchematicPaginationBox extends PaginationBox { + private final String prefix; + private final File[] files; + + public SchematicPaginationBox(String rootDir, File[] files, String pageCommand) { + super("Available schematics", pageCommand); + this.prefix = rootDir == null ? "" : rootDir; + this.files = files; + } + + @Override + public Component getComponent(int number) { + checkArgument(number < files.length - 1 && number >= 0); + File file = files[number]; + Multimap exts = ClipboardFormats.getFileExtensionMap(); + String format = exts.get(Files.getFileExtension(file.getName())) + .stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown"); + boolean inRoot = file.getParentFile().getName().equals(prefix); + + String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1]; + + return TextComponent.builder() + .content("") + .append(TextComponent.of("[L]") + .color(TextColor.GOLD) + .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem load " + path)) + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load")))) + .append(Component.space()) + .append(TextComponent.of(path) + .color(TextColor.DARK_GREEN) + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format)))) + .build(); + } + + @Override + public int getComponentsSize() { + return files.length; + } +} From 6e016a66f0fb0a2225625252188ec5eee14f0678 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sun, 28 Apr 2019 16:05:01 +1000 Subject: [PATCH 082/366] Fixed //size on clipboards --- .../worldedit/command/SelectionCommands.java | 28 ++++++++----------- .../component/SchematicPaginationBox.java | 19 +++++++++++++ 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index d2e2a3708..8a62dc529 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -457,33 +457,27 @@ public class SelectionCommands { public void size(Player player, LocalSession session, @Switch(name = 'c', desc = "Get clipboard info instead") boolean clipboardInfo) throws WorldEditException { + Region region; if (clipboardInfo) { ClipboardHolder holder = session.getClipboard(); Clipboard clipboard = holder.getClipboard(); - Region region = clipboard.getRegion(); - BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()); + region = clipboard.getRegion(); + BlockVector3 origin = clipboard.getOrigin(); - - player.print("Cuboid dimensions (max - min): " + size); player.print("Offset: " + origin); - player.print("Cuboid distance: " + size.distance(BlockVector3.ONE)); - player.print("# of blocks: " + (size.getX() * size.getY() * size.getZ())); - return; - } + } else { + region = session.getSelection(player.getWorld()); - Region region = session.getSelection(player.getWorld()); + player.print("Type: " + session.getRegionSelector(player.getWorld()).getTypeName()); + + for (String line : session.getRegionSelector(player.getWorld()).getInformationLines()) { + player.print(line); + } + } BlockVector3 size = region.getMaximumPoint() .subtract(region.getMinimumPoint()) .add(1, 1, 1); - player.print("Type: " + session.getRegionSelector(player.getWorld()) - .getTypeName()); - - for (String line : session.getRegionSelector(player.getWorld()) - .getInformationLines()) { - player.print(line); - } - player.print("Size: " + size); player.print("Cuboid distance: " + region.getMaximumPoint().distance(region.getMinimumPoint())); player.print("# of blocks: " + region.getArea()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java index 6a1f0712c..eb9598a49 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java @@ -1,3 +1,22 @@ +/* + * 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.util.formatting.component; import com.google.common.collect.Multimap; From 32d4b36419f734617d48765b568f0e5c74354d37 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sun, 28 Apr 2019 17:05:37 +1000 Subject: [PATCH 083/366] Fixed //drawsel --- worldedit-core/src/main/assembly/default.xml | 34 ------------------- .../worldedit/command/GeneralCommands.java | 2 +- .../worldedit/command/SchematicCommands.java | 2 +- .../worldedit/command/UtilityCommands.java | 6 ++-- 4 files changed, 4 insertions(+), 40 deletions(-) delete mode 100644 worldedit-core/src/main/assembly/default.xml diff --git a/worldedit-core/src/main/assembly/default.xml b/worldedit-core/src/main/assembly/default.xml deleted file mode 100644 index e6c1849ab..000000000 --- a/worldedit-core/src/main/assembly/default.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - false - - tar.gz - tar.bz2 - zip - - - - ${project.build.directory}/${artifactId}-${project.version}.jar - WorldEdit.jar - / - false - - - README.html - / - true - - - - - - LICENSE.txt - CHANGELOG.txt - contrib/craftscripts/* - - - - diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 220b30de2..08e46addc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -161,7 +161,7 @@ public class GeneralCommands { ) @CommandPermissions("worldedit.drawsel") public void drawSelection(Player player, LocalSession session, - @Arg(desc = "The new draw selection state", def = "toggle") + @Arg(desc = "The new draw selection state", def = "") Boolean drawSelection) throws WorldEditException { if (!WorldEdit.getInstance().getConfiguration().serverSideCUI) { throw new DisallowedUsageException("This functionality is disabled in the configuration!"); 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 fe4f5f1de..829af8a9c 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 @@ -308,7 +308,7 @@ public class SchematicCommands { return res; }); - String pageCommand = actor.isPlayer() ? "/schem list -p %page%" + (oldFirst ? " -d" : newFirst ? " -n" : "") : null; + String pageCommand = actor.isPlayer() ? "//schem list -p %page%" + (oldFirst ? " -d" : newFirst ? " -n" : "") : null; PaginationBox paginationBox = new SchematicPaginationBox(worldEdit.getConfiguration().saveDir, files, pageCommand); actor.print(paginationBox.create(page)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 37facdddb..da09cc5b3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.command; +import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; + import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalConfiguration; @@ -51,7 +53,6 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CylinderRegion; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.formatting.component.InvalidComponentException; import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; @@ -69,8 +70,6 @@ import java.util.List; import java.util.Locale; import java.util.function.Supplier; -import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; - /** * Utility commands. */ @@ -386,7 +385,6 @@ public class UtilityCommands { LocalConfiguration config = we.getConfiguration(); Player player = actor instanceof Player ? (Player) actor : null; - int defaultRadius = config.butcherDefaultRadius; if (radius == null) { radius = config.butcherDefaultRadius; } else if (radius < -1) { From f7670f7812d47868932a698bcca5a3c154089caa Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sun, 28 Apr 2019 18:47:28 +1000 Subject: [PATCH 084/366] Temporary fix for forge having terrible classpath issues. --- .../worldedit/util/io/ResourceLoader.java | 43 +++++++++++++++++++ .../world/registry/BundledBlockData.java | 3 +- .../world/registry/BundledItemData.java | 3 +- .../world/registry/LegacyMapper.java | 3 +- 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java new file mode 100644 index 000000000..09ac4724f --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java @@ -0,0 +1,43 @@ +/* + * 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.util.io; + +import java.io.IOException; +import java.net.URL; + +public class ResourceLoader { + + private ResourceLoader() { + } + + public static URL getResource(Class clazz, String name) throws IOException { + URL url = clazz.getResource(name); + if (url == null) { + try { + return new URL("modjar://worldedit/" + clazz.getName().substring(0, clazz.getName().lastIndexOf('.')).replace(".", "/") + "/" + + name); + } catch (Exception e) { + // Not forge. + } + throw new IOException("Could not find " + name); + } + return url; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java index 4dffdb38f..76cd902ef 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java @@ -25,6 +25,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.gson.VectorAdapter; +import com.sk89q.worldedit.util.io.ResourceLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,7 +75,7 @@ public class BundledBlockData { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); Gson gson = gsonBuilder.create(); - URL url = BundledBlockData.class.getResource("blocks.json"); + URL url = ResourceLoader.getResource(BundledBlockData.class, "blocks.json"); if (url == null) { throw new IOException("Could not find blocks.json"); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java index 4bdac0c8a..4e1af0422 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java @@ -25,6 +25,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.gson.VectorAdapter; +import com.sk89q.worldedit.util.io.ResourceLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,7 +75,7 @@ public class BundledItemData { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); Gson gson = gsonBuilder.create(); - URL url = BundledItemData.class.getResource("items.json"); + URL url = ResourceLoader.getResource(BundledItemData.class,"items.json"); if (url == null) { throw new IOException("Could not find items.json"); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java index a41814abc..05acbeb1d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java @@ -29,6 +29,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.gson.VectorAdapter; +import com.sk89q.worldedit.util.io.ResourceLoader; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; @@ -74,7 +75,7 @@ public class LegacyMapper { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); Gson gson = gsonBuilder.disableHtmlEscaping().create(); - URL url = LegacyMapper.class.getResource("legacy.json"); + URL url = ResourceLoader.getResource(LegacyMapper.class, "legacy.json"); if (url == null) { throw new IOException("Could not find legacy.json"); } From d48702aad69523ef580d0133eead374d39a4a2a0 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 28 Apr 2019 10:56:21 -0400 Subject: [PATCH 085/366] Fix schematic id conversion for entities with multiple renames. --- .../clipboard/io/MCEditSchematicReader.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) 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 53ec62dae..71005ad00 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 @@ -287,13 +287,10 @@ public class MCEditSchematicReader extends NBTSchematicReader { case "ArmorStand": return "armor_stand"; case "CaveSpider": return "cave_spider"; case "MinecartChest": return "chest_minecart"; - case "MinecartCommandBlock": return "commandblock_minecart"; case "DragonFireball": return "dragon_fireball"; case "ThrownEgg": return "egg"; - case "EnderCrystal": return "ender_crystal"; case "EnderDragon": return "ender_dragon"; case "ThrownEnderpearl": return "ender_pearl"; - case "EyeOfEnderSignal": return "eye_of_ender_signal"; case "FallingSand": return "falling_block"; case "FireworksRocketEntity": return "fireworks_rocket"; case "MinecartFurnace": return "furnace_minecart"; @@ -317,15 +314,23 @@ public class MCEditSchematicReader extends NBTSchematicReader { case "VillagerGolem": return "villager_golem"; case "WitherBoss": return "wither"; case "WitherSkull": return "wither_skull"; - case "ThrownExpBottle": return "xp_bottle"; - case "XPOrb": return "xp_orb"; case "PigZombie": return "zombie_pigman"; - case "xp_orb": return "experience_orb"; - case "xp_bottle": return "experience_bottle"; - case "eye_of_ender_signal": return "eye_of_ender"; - case "ender_crystal": return "end_crystal"; + case "XPOrb": + case "xp_orb": + return "experience_orb"; + case "ThrownExpBottle": + case "xp_bottle": + return "experience_bottle"; + case "EyeOfEnderSignal": + case "eye_of_ender_signal": + return "eye_of_ender"; + case "EnderCrystal": + case "ender_crystal": + return "end_crystal"; case "fireworks_rocket": return "firework_rocket"; - case "commandblock_minecart": return "command_block_minecart"; + case "MinecartCommandBlock": + case "commandblock_minecart": + return "command_block_minecart"; case "snowman": return "snow_golem"; case "villager_golem": return "iron_golem"; case "evocation_fangs": return "evoker_fangs"; From 6255ccce386214985c1c9d0ea5d2fb0ef6d3df16 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 28 Apr 2019 17:27:33 -0700 Subject: [PATCH 086/366] Minor bug fixes --- .../worldedit/command/ApplyBrushCommands.java | 1 + .../worldedit/command/PaintBrushCommands.java | 1 + .../command/argument/FactoryConverter.java | 3 ++- .../platform/PlatformCommandManager.java | 5 +++-- .../command/WorldEditExceptionConverter.java | 13 ++++++++---- .../parametric/ExceptionConverterHelper.java | 21 ++++++++++--------- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java index d324c3484..285dd272c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java @@ -84,6 +84,7 @@ public class ApplyBrushCommands { builder.addParts(REGION_FACTORY, RADIUS); builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TextComponent.of("Type of brush to use")) .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() .build()); }); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java index c365e129f..9b1aeef94 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java @@ -89,6 +89,7 @@ public class PaintBrushCommands { builder.addParts(REGION_FACTORY, RADIUS, DENSITY); builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TextComponent.of("Type of brush to use")) .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() .build()); }); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index 2e7eedb72..0de24e5a7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -36,6 +36,7 @@ import com.sk89q.worldedit.world.World; import org.enginehub.piston.CommandManager; import org.enginehub.piston.converter.ArgumentConverter; import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; import org.enginehub.piston.converter.SuccessfulConversion; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; @@ -86,7 +87,7 @@ public class FactoryConverter implements ArgumentConverter { factoryExtractor.apply(worldEdit).parseFromInput(argument, parserContext) ); } catch (InputParseException e) { - throw new IllegalArgumentException(e); + return FailedConversion.from(e); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 34b5e0e82..bfc362a6d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -256,6 +256,7 @@ public final class PlatformCommandManager { registration, instance ); + additionalConfig.accept(manager); cmd.addPart(SubCommandPart.builder(TranslatableComponent.of("worldedit.argument.action"), TextComponent.of("Sub-command to run.")) @@ -443,7 +444,7 @@ public final class PlatformCommandManager { Request.reset(); Actor actor = platformManager.createProxyActor(event.getActor()); - String[] split = commandDetection(event.getArguments().split(" ")); + String[] split = commandDetection(event.getArguments().substring(1).split(" ")); // No command found! if (!commandManager.containsCommand(split[0])) { @@ -511,7 +512,7 @@ public final class PlatformCommandManager { actor.print(TextComponent.builder("Usage: ") .color(TextColor.RED) .append(TextComponent.of("/", ColorConfig.getMainText())) - .append(HelpGenerator.create(cmd).getUsage()) + .append(HelpGenerator.create(e.getCommandParseResult()).getUsage()) .build()); } } catch (CommandExecutionException e) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java index a11294527..3dfafe349 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.internal.command; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.DisallowedItemException; import com.sk89q.worldedit.EmptyClipboardException; @@ -35,7 +33,6 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.InsufficientArgumentsException; import com.sk89q.worldedit.command.tool.InvalidToolBindException; -import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.util.command.parametric.ExceptionConverterHelper; @@ -45,11 +42,13 @@ import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException; import com.sk89q.worldedit.util.io.file.FilenameResolutionException; import com.sk89q.worldedit.util.io.file.InvalidFilenameException; import org.enginehub.piston.exception.CommandException; -import org.enginehub.piston.exception.ConditionFailedException; +import org.enginehub.piston.exception.UsageException; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.google.common.base.Preconditions.checkNotNull; + /** * converts WorldEdit exceptions and converts them into {@link CommandException}s. */ @@ -173,4 +172,10 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { throw newCommandException(e.getMessage(), e); } + // Prevent investigation into UsageExceptions + @ExceptionMatch + public void convert(UsageException e) throws CommandException { + throw e; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java index f13557487..039bd4cde 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.util.command.parametric; +import com.google.common.collect.ImmutableList; import com.sk89q.minecraft.util.commands.WrappedCommandException; import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.CommandExecutionException; @@ -32,24 +33,24 @@ import java.util.List; /** * An implementation of an {@link ExceptionConverter} that automatically calls * the correct method defined on this object. - * + * *

Only public methods will be used. Methods will be called in order of decreasing * levels of inheritance (between classes where one inherits the other). For two * different inheritance branches, the order between them is undefined.

*/ public abstract class ExceptionConverterHelper implements ExceptionConverter { - + private final List handlers; @SuppressWarnings("unchecked") public ExceptionConverterHelper() { List handlers = new ArrayList<>(); - + for (Method method : this.getClass().getMethods()) { if (method.getAnnotation(ExceptionMatch.class) == null) { continue; } - + Class[] parameters = method.getParameterTypes(); if (parameters.length == 1) { Class cls = parameters[0]; @@ -59,9 +60,9 @@ public abstract class ExceptionConverterHelper implements ExceptionConverter { } } } - + Collections.sort(handlers); - + this.handlers = handlers; } @@ -76,18 +77,18 @@ public abstract class ExceptionConverterHelper implements ExceptionConverter { if (e.getCause() instanceof CommandException) { throw (CommandException) e.getCause(); } - throw new CommandExecutionException(e, null); + throw new CommandExecutionException(e, ImmutableList.of()); } catch (IllegalArgumentException | IllegalAccessException e) { - throw new CommandExecutionException(e, null); + throw new CommandExecutionException(e, ImmutableList.of()); } } } } - + private static class ExceptionHandler implements Comparable { final Class cls; final Method method; - + private ExceptionHandler(Class cls, Method method) { this.cls = cls; this.method = method; From 2580a0cf97d70ec7127a08675aa1be34600e050f Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 28 Apr 2019 17:30:58 -0700 Subject: [PATCH 087/366] Use 'shape' instead of 'regionFactory' in user-facing ctx --- .../worldedit/command/ApplyBrushCommands.java | 2 +- .../worldedit/command/BrushCommands.java | 24 +++++++++---------- .../worldedit/command/PaintBrushCommands.java | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java index 285dd272c..cfab5fbae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java @@ -56,7 +56,7 @@ import static org.enginehub.piston.part.CommandParts.arg; @CommandContainer public class ApplyBrushCommands { - private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("regionFactory"), TextComponent.of("The shape of the region")) + private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("shape"), TextComponent.of("The shape of the region")) .defaultsTo(ImmutableList.of()) .ofTypes(ImmutableList.of(Key.of(RegionFactory.class))) .build(); 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 0b29fdede..26553a087 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 @@ -296,7 +296,7 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.deform") public void deform(Player player, LocalSession localSession, @Arg(desc = "The shape of the region") - RegionFactory regionFactory, + RegionFactory shape, @Arg(desc = "The size of the brush", def = "5") double radius, @Arg(desc = "Expression to apply", def = "y-=0.2") @@ -313,7 +313,7 @@ public class BrushCommands { deform.setOffset(localSession.getPlacementPosition(player).toVector3()); } setOperationBasedBrush(player, localSession, radius, - deform, regionFactory, "worldedit.brush.deform"); + deform, shape, "worldedit.brush.deform"); } @Command( @@ -323,13 +323,13 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.set") public void set(Player player, LocalSession localSession, @Arg(desc = "The shape of the region") - RegionFactory regionFactory, + RegionFactory shape, @Arg(desc = "The size of the brush", def = "5") double radius, @Arg(desc = "The pattern of blocks to set") Pattern pattern) throws WorldEditException { setOperationBasedBrush(player, localSession, radius, - new Apply(new ReplaceFactory(pattern)), regionFactory, "worldedit.brush.set"); + new Apply(new ReplaceFactory(pattern)), shape, "worldedit.brush.set"); } @Command( @@ -339,7 +339,7 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.forest") public void forest(Player player, LocalSession localSession, @Arg(desc = "The shape of the region") - RegionFactory regionFactory, + RegionFactory shape, @Arg(desc = "The size of the brush", def = "5") double radius, @Arg(desc = "The density of the brush", def = "20") @@ -347,7 +347,7 @@ public class BrushCommands { @Arg(desc = "The type of tree to use") TreeGenerator.TreeType type) throws WorldEditException { setOperationBasedBrush(player, localSession, radius, - new Paint(new TreeGeneratorFactory(type), density / 100), regionFactory, "worldedit.brush.forest"); + new Paint(new TreeGeneratorFactory(type), density / 100), shape, "worldedit.brush.forest"); } @Command( @@ -357,11 +357,11 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.raise") public void raise(Player player, LocalSession localSession, @Arg(desc = "The shape of the region") - RegionFactory regionFactory, + RegionFactory shape, @Arg(desc = "The size of the brush", def = "5") double radius) throws WorldEditException { setOperationBasedBrush(player, localSession, radius, - new Deform("y-=1"), regionFactory, "worldedit.brush.raise"); + new Deform("y-=1"), shape, "worldedit.brush.raise"); } @Command( @@ -371,22 +371,22 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.lower") public void lower(Player player, LocalSession localSession, @Arg(desc = "The shape of the region") - RegionFactory regionFactory, + RegionFactory shape, @Arg(desc = "The size of the brush", def = "5") double radius) throws WorldEditException { setOperationBasedBrush(player, localSession, radius, - new Deform("y+=1"), regionFactory, "worldedit.brush.lower"); + new Deform("y+=1"), shape, "worldedit.brush.lower"); } static void setOperationBasedBrush(Player player, LocalSession session, double radius, Contextual factory, - RegionFactory regionFactory, + RegionFactory shape, String permission) throws WorldEditException { WorldEdit.getInstance().checkMaxBrushRadius(radius); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); tool.setSize(radius); tool.setFill(null); - tool.setBrush(new OperationFactoryBrush(factory, regionFactory, session), permission); + tool.setBrush(new OperationFactoryBrush(factory, shape, session), permission); player.print("Set brush to " + factory); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java index 9b1aeef94..4f4064827 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java @@ -56,7 +56,7 @@ import static org.enginehub.piston.part.CommandParts.arg; @CommandContainer public class PaintBrushCommands { - private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("regionFactory"), TextComponent.of("The shape of the region")) + private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("shape"), TextComponent.of("The shape of the region")) .defaultsTo(ImmutableList.of()) .ofTypes(ImmutableList.of(Key.of(RegionFactory.class))) .build(); From 7d85df4575b9db73dae5efea38564363005fabfc Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 28 Apr 2019 17:35:28 -0700 Subject: [PATCH 088/366] Cache SNAPSHOTs for only five minutes, since they change often --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index 41de17bb8..43ec9605a 100644 --- a/build.gradle +++ b/build.gradle @@ -87,6 +87,11 @@ subprojects { maven { url "http://maven.sk89q.com/repo/" } maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } } + configurations.all { + resolutionStrategy { + cacheChangingModulesFor 5, 'minutes' + } + } } configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) { From d4fce65abc18257fdb4c14a864fa107b0b7b0b40 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 28 Apr 2019 21:42:45 -0700 Subject: [PATCH 089/366] A few command fixes --- .../com/sk89q/worldedit/command/BrushCommands.java | 10 +++++++--- .../com/sk89q/worldedit/command/RegionCommands.java | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) 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 26553a087..b6433a206 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 @@ -88,7 +88,9 @@ public class BrushCommands { desc = "Choose the sphere brush" ) @CommandPermissions("worldedit.brush.sphere") - public void sphereBrush(Player player, LocalSession session, Pattern fill, + public void sphereBrush(Player player, LocalSession session, + @Arg(desc = "The pattern of blocks to set") + Pattern fill, @Arg(desc = "The radius of the sphere", def = "2") double radius, @Switch(name = 'h', desc = "Create hollow spheres instead") @@ -114,7 +116,9 @@ public class BrushCommands { desc = "Choose the cylinder brush" ) @CommandPermissions("worldedit.brush.cylinder") - public void cylinderBrush(Player player, LocalSession session, Pattern fill, + public void cylinderBrush(Player player, LocalSession session, + @Arg(desc = "The pattern of blocks to set") + Pattern fill, @Arg(desc = "The radius of the cylinder", def = "2") double radius, @Arg(desc = "The height of the cylinder", def = "1") @@ -152,7 +156,7 @@ public class BrushCommands { boolean pasteEntities, @Switch(name = 'b', desc = "Paste biomes if available") boolean pasteBiomes, - @ArgFlag(name = 'm', desc = "Skip blocks matching this mask", def = "") + @ArgFlag(name = 'm', desc = "Skip blocks matching this mask in the clipboard", def = "") Mask sourceMask) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); Clipboard clipboard = holder.getClipboard(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index ae4333c04..b016128e8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -177,7 +177,7 @@ public class RegionCommands { @Arg(desc = "The mask representing blocks to replace", def = "") Mask from, @Arg(desc = "The pattern of blocks to replace with") - Pattern to) throws WorldEditException { + Pattern to) throws WorldEditException { if (from == null) { from = new ExistingBlockMask(editSession); } From 82c484643674968dc400f0d23e5c6e8c5df33081 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 28 Apr 2019 22:03:54 -0700 Subject: [PATCH 090/366] Add more variable args for expressions, quoting --- .../worldedit/command/GenerationCommands.java | 12 +-- .../worldedit/command/RegionCommands.java | 6 +- .../worldedit/command/UtilityCommands.java | 6 +- .../platform/PlatformCommandManager.java | 8 +- .../util/command/CommandArgParser.java | 85 +++++++++++++++++++ 5 files changed, 103 insertions(+), 14 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java 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 962243c9f..646672d2f 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 @@ -273,8 +273,8 @@ public class GenerationCommands { @Selection Region region, @Arg(desc = "The pattern of blocks to set") Pattern pattern, - @Arg(desc = "Expression to test block placement locations and set block type") - String expression, + @Arg(desc = "Expression to test block placement locations and set block type", variable = true) + List expression, @Switch(name = 'h', desc = "Generate a hollow shape") boolean hollow, @Switch(name = 'r', desc = "Use the game's coordinate origin") @@ -312,7 +312,7 @@ public class GenerationCommands { } try { - final int affected = editSession.makeShape(region, zero, unit, pattern, expression, hollow, session.getTimeout()); + final int affected = editSession.makeShape(region, zero, unit, pattern, String.join(" ", expression), hollow, session.getTimeout()); player.findFreePosition(); player.print(affected + " block(s) have been created."); return affected; @@ -334,8 +334,8 @@ public class GenerationCommands { @Selection Region region, @Arg(desc = "The biome type to set") BiomeType target, - @Arg(desc = "Expression to test block placement locations and set biome type") - String expression, + @Arg(desc = "Expression to test block placement locations and set biome type", variable = true) + List expression, @Switch(name = 'h', desc = "Generate a hollow shape") boolean hollow, @Switch(name = 'r', desc = "Use the game's coordinate origin") @@ -372,7 +372,7 @@ public class GenerationCommands { } try { - final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow, session.getTimeout()); + final int affected = editSession.makeBiomeShape(region, zero, unit, target, String.join(" ", expression), hollow, session.getTimeout()); player.findFreePosition(); player.print("" + affected + " columns affected."); return affected; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index b016128e8..a8591e1de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -382,8 +382,8 @@ public class RegionCommands { @Logging(ALL) public int deform(Player player, LocalSession session, EditSession editSession, @Selection Region region, - @Arg(desc = "The expression to use") - String expression, + @Arg(desc = "The expression to use", variable = true) + List expression, @Switch(name = 'r', desc = "Use the game's coordinate origin") boolean useRawCoords, @Switch(name = 'o', desc = "Use the selection's center as origin") @@ -410,7 +410,7 @@ public class RegionCommands { } try { - final int affected = editSession.deformRegion(region, zero, unit, expression, session.getTimeout()); + final int affected = editSession.deformRegion(region, zero, unit, String.join(" ", expression), session.getTimeout()); player.findFreePosition(); player.print(affected + " block(s) have been deformed."); return affected; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index da09cc5b3..0bdcf7425 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -492,10 +492,10 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.calc") public void calc(Actor actor, - @Arg(desc = "Expression to evaluate") - String input) { + @Arg(desc = "Expression to evaluate", variable = true) + List input) { try { - Expression expression = Expression.compile(input); + Expression expression = Expression.compile(String.join(" ", input)); double result = expression.evaluate( new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout()); String formatted = formatter.format(result); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index bfc362a6d..be9a03500 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -89,12 +89,12 @@ import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.command.CommandArgParser; import com.sk89q.worldedit.util.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; @@ -439,12 +439,16 @@ public final class PlatformCommandManager { return split; } + private String[] parseArgs(String input) { + return new CommandArgParser(input).parseArgs().toArray(String[]::new); + } + @Subscribe public void handleCommand(CommandEvent event) { Request.reset(); Actor actor = platformManager.createProxyActor(event.getActor()); - String[] split = commandDetection(event.getArguments().substring(1).split(" ")); + String[] split = commandDetection(parseArgs(event.getArguments().substring(1))); // No command found! if (!commandManager.containsCommand(split[0])) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java new file mode 100644 index 000000000..293664a07 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java @@ -0,0 +1,85 @@ +package com.sk89q.worldedit.util.command; + +import java.util.stream.Stream; + +public class CommandArgParser { + + private enum State { + NORMAL, + QUOTE + } + + private final Stream.Builder args = Stream.builder(); + private final StringBuilder currentArg = new StringBuilder(); + private final String input; + private int index = 0; + private State state = State.NORMAL; + + public CommandArgParser(String input) { + this.input = input; + } + + public Stream parseArgs() { + for (; index < input.length(); index++) { + char c = input.charAt(index); + switch (state) { + case NORMAL: + handleNormal(c); + break; + case QUOTE: + handleQuote(c); + } + } + finishArg(true); + return args.build(); + } + + private void handleNormal(char c) { + switch (c) { + case '"': + state = State.QUOTE; + break; + case ' ': + finishArg(true); + break; + case '\\': + if (index + 1 < input.length()) { + index++; + } + appendChar(input.charAt(index)); + break; + default: + appendChar(c); + } + } + + private void handleQuote(char c) { + switch (c) { + case '"': + state = State.NORMAL; + finishArg(false); + break; + case '\\': + if (index + 1 < input.length()) { + index++; + } + appendChar(input.charAt(index)); + break; + default: + appendChar(c); + } + } + + private void finishArg(boolean requireText) { + if (currentArg.length() == 0 && requireText) { + return; + } + args.add(currentArg.toString()); + currentArg.setLength(0); + } + + private void appendChar(char c) { + currentArg.append(c); + } + +} From 462843c3df4834600208f31a4ae779891ad8f448 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 28 Apr 2019 22:07:08 -0700 Subject: [PATCH 091/366] Add license --- .../util/command/CommandArgParser.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java index 293664a07..5c414d08a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java @@ -1,3 +1,22 @@ +/* + * 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.util.command; import java.util.stream.Stream; From 6c21ae5c8339d205f9ed1d12e106f01f82bfeb56 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 28 Apr 2019 22:09:48 -0700 Subject: [PATCH 092/366] Drop old calc message --- .../main/java/com/sk89q/worldedit/command/UtilityCommands.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 0bdcf7425..0e18dbcbd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -501,9 +501,6 @@ public class UtilityCommands { String formatted = formatter.format(result); actor.print(SubtleFormat.wrap(input + " = ") .append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE))); - //actor.print(SubtleFormat.wrap(input).append(Component.newline()) - // .append(SubtleFormat.wrap("= ")) - // .append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE))); } catch (EvaluationException e) { actor.printError(String.format( "'%s' could not be evaluated (error: %s)", input, e.getMessage())); From 8baf221c954534b04934f3ad531cb439937b8894 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 29 Apr 2019 17:38:26 -0400 Subject: [PATCH 093/366] Hide help buttons in //sel selector box. --- .../worldedit/command/SelectionCommands.java | 1 + .../formatting/component/CommandListBox.java | 21 ++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 8a62dc529..bac02819a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -619,6 +619,7 @@ public class SelectionCommands { case UNKNOWN: default: CommandListBox box = new CommandListBox("Selection modes", null); + box.setHidingHelp(true); TextComponentProducer contents = box.getContents(); contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java index 4c08f6863..e1b889059 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -31,6 +31,7 @@ import java.util.List; public class CommandListBox extends PaginationBox { private List commands = Lists.newArrayList(); + private boolean hideHelp; /** * Create a new box. @@ -43,7 +44,7 @@ public class CommandListBox extends PaginationBox { @Override public Component getComponent(int number) { - return commands.get(number).createComponent(); + return commands.get(number).createComponent(hideHelp); } @Override @@ -63,6 +64,14 @@ public class CommandListBox extends PaginationBox { commands.add(new CommandEntry(alias, description, insertion)); } + public boolean isHidingHelp() { + return hideHelp; + } + + public void setHidingHelp(boolean hideHelp) { + this.hideHelp = hideHelp; + } + private static class CommandEntry { private final String alias; private final Component description; @@ -74,11 +83,13 @@ public class CommandListBox extends PaginationBox { this.insertion = insertion; } - Component createComponent() { + Component createComponent(boolean hideHelp) { TextComponentProducer line = new TextComponentProducer(); - line.append(SubtleFormat.wrap("? ") - .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "//help " + insertion)) - .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help")))); + if (!hideHelp) { + line.append(SubtleFormat.wrap("? ") + .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "//help " + insertion)) + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help")))); + } TextComponent command = TextComponent.of(alias, TextColor.GOLD); if (insertion == null) { line.append(command); From 3c04a83852f66017be902117cc13ea89d56fe5ae Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 29 Apr 2019 17:39:30 -0400 Subject: [PATCH 094/366] Add nicer error when using player commands as console. Also fix slash counts for Bukkit. --- .../main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java | 4 ++-- .../worldedit/extension/platform/PlatformCommandManager.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) 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 1c824dcec..99652499d 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 @@ -289,7 +289,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // code of WorldEdit expects it String[] split = new String[args.length + 1]; System.arraycopy(args, 0, split, 1, args.length); - split[0] = cmd.getName(); + split[0] = "/" + cmd.getName(); CommandEvent event = new CommandEvent(wrapCommandSender(sender), Joiner.on(" ").join(split)); getWorldEdit().getEventBus().post(event); @@ -303,7 +303,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // code of WorldEdit expects it String[] split = new String[args.length + 1]; System.arraycopy(args, 0, split, 1, args.length); - split[0] = cmd.getName(); + split[0] = "/" + cmd.getName(); CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), Joiner.on(" ").join(split)); getWorldEdit().getEventBus().post(event); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index be9a03500..f1f7380a4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -469,6 +469,10 @@ public final class PlatformCommandManager { store.injectValue(Key.of(Actor.class), ValueProvider.constant(actor)); if (actor instanceof Player) { store.injectValue(Key.of(Player.class), ValueProvider.constant((Player) actor)); + } else { + store.injectValue(Key.of(Player.class), context -> { + throw new CommandException(TextComponent.of("This command must be used with a player."), ImmutableList.of()); + }); } store.injectValue(Key.of(Arguments.class), ValueProvider.constant(event::getArguments)); store.injectValue(Key.of(LocalSession.class), From d0f9a71d53e1a3f76bb8fe344ce898486cb37af8 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 29 Apr 2019 21:57:03 -0700 Subject: [PATCH 095/366] Re-implement many converters using Piston utility converters --- .../command/argument/BooleanConverter.java | 48 ++++--------- .../CommaSeparatedValuesConverter.java | 2 +- .../command/argument/DirectionConverter.java | 5 +- .../command/argument/EnumConverter.java | 71 ++++--------------- .../argument/ExpandAmountConverter.java | 9 +-- .../argument/RegionFactoryConverter.java | 51 ++++--------- .../command/argument/RegistryConverter.java | 66 ++++++++++------- .../sk89q/worldedit/registry/Registry.java | 4 ++ 8 files changed, 91 insertions(+), 165 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java index a024cb792..5d4ad5891 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java @@ -19,49 +19,27 @@ package com.sk89q.worldedit.command.argument; -import com.google.common.collect.ImmutableSortedSet; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.google.common.collect.ImmutableSetMultimap; import org.enginehub.piston.CommandManager; -import org.enginehub.piston.converter.ArgumentConverter; -import org.enginehub.piston.converter.ConversionResult; -import org.enginehub.piston.converter.FailedConversion; -import org.enginehub.piston.converter.SuccessfulConversion; -import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.converter.MultiKeyConverter; import org.enginehub.piston.inject.Key; -public class BooleanConverter implements ArgumentConverter { +public class BooleanConverter { public static void register(CommandManager commandManager) { - commandManager.registerConverter(Key.of(Boolean.class), new BooleanConverter()); + commandManager.registerConverter(Key.of(Boolean.class), + MultiKeyConverter.builder( + ImmutableSetMultimap.builder() + .putAll(false, "off", "f", "false", "n", "no") + .putAll(true, "on", "t", "true", "y", "yes") + .build() + ) + .errorMessage(arg -> "Not a boolean value" + arg) + .build() + ); } - private static final ImmutableSortedSet TRUE = ImmutableSortedSet - .orderedBy(String.CASE_INSENSITIVE_ORDER) - .add("on", "t", "true", "y", "yes") - .build(); - - private static final ImmutableSortedSet FALSE = ImmutableSortedSet - .orderedBy(String.CASE_INSENSITIVE_ORDER) - .add("off", "f", "false", "n", "no") - .build(); - private BooleanConverter() { } - @Override - public Component describeAcceptableArguments() { - return TextComponent.of("on|off|true|false"); - } - - @Override - public ConversionResult convert(String argument, InjectedValueAccess context) { - if (TRUE.contains(argument)) { - return SuccessfulConversion.fromSingle(true); - } - if (FALSE.contains(argument)) { - return SuccessfulConversion.fromSingle(false); - } - return FailedConversion.from(new IllegalArgumentException("Not a strictly boolean value: " + argument)); - } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java index ba35fa6e4..7479ff375 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java @@ -71,7 +71,7 @@ public class CommaSeparatedValuesConverter implements ArgumentConverter { @Override public List getSuggestions(String input) { - String lastInput = Iterables.getLast(COMMA.split(input)); + String lastInput = Iterables.getLast(COMMA.split(input), ""); return delegate.getSuggestions(lastInput); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java index f9e1c4f1f..aacfe4bf5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java @@ -41,6 +41,7 @@ import org.enginehub.piston.inject.Key; import java.util.List; import static java.util.stream.Collectors.toList; +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; public class DirectionConverter implements ArgumentConverter { @@ -113,8 +114,6 @@ public class DirectionConverter implements ArgumentConverter { @Override public List getSuggestions(String input) { - return suggestions.stream() - .filter(s -> s.startsWith(input)) - .collect(toList()); + return limitByPrefix(suggestions.stream(), input); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java index a408a2793..14a49b38c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java @@ -19,31 +19,20 @@ package com.sk89q.worldedit.command.argument; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSortedMap; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import org.enginehub.piston.CommandManager; import org.enginehub.piston.converter.ArgumentConverter; -import org.enginehub.piston.converter.ConversionResult; -import org.enginehub.piston.converter.FailedConversion; -import org.enginehub.piston.converter.SuccessfulConversion; -import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.converter.MultiKeyConverter; import org.enginehub.piston.inject.Key; import javax.annotation.Nullable; import java.util.EnumSet; import java.util.Set; import java.util.function.Function; -import java.util.stream.Stream; -import static com.google.common.base.Preconditions.checkState; -import static java.util.stream.Collectors.joining; - -public class EnumConverter> implements ArgumentConverter { +public class EnumConverter { public static void register(CommandManager commandManager) { commandManager.registerConverter(Key.of(SelectorChoice.class), @@ -58,59 +47,25 @@ public class EnumConverter> implements ArgumentConverter { null)); } - private static > EnumConverter basic(Class enumClass) { + private static > ArgumentConverter basic(Class enumClass) { return full(enumClass, e -> ImmutableSet.of(e.name()), null); } - private static > EnumConverter basic(Class enumClass, E unknownValue) { + private static > ArgumentConverter basic(Class enumClass, E unknownValue) { return full(enumClass, e -> ImmutableSet.of(e.name()), unknownValue); } - private static > EnumConverter full(Class enumClass, - Function> lookupKeys, - @Nullable E unknownValue) { - return new EnumConverter<>(enumClass, lookupKeys, unknownValue); + private static > ArgumentConverter full(Class enumClass, + Function> lookupKeys, + @Nullable E unknownValue) { + return MultiKeyConverter.from( + EnumSet.allOf(enumClass), + lookupKeys, + unknownValue + ); } - private final Component choices; - private final ImmutableMap map; - @Nullable - private final E unknownValue; - - private EnumConverter(Class enumClass, - Function> lookupKeys, - @Nullable E unknownValue) { - ImmutableSortedMap.Builder map = ImmutableSortedMap.orderedBy(String.CASE_INSENSITIVE_ORDER); - Stream.Builder> choices = Stream.builder(); - EnumSet validValues = EnumSet.allOf(enumClass); - if (unknownValue != null) { - validValues.remove(unknownValue); - } - for (E e : validValues) { - Set keys = lookupKeys.apply(e); - checkState(keys.size() > 0, "No lookup keys for enum value %s", e); - choices.add(keys); - for (String key : keys) { - map.put(key, e); - } - } - this.choices = TextComponent.of(choices.build() - .map(choice -> choice.stream().collect(joining("|", "[", "]"))) - .collect(joining("|"))); - this.map = map.build(); - this.unknownValue = unknownValue; + private EnumConverter() { } - @Override - public Component describeAcceptableArguments() { - return choices; - } - - @Override - public ConversionResult convert(String argument, InjectedValueAccess context) { - E result = map.getOrDefault(argument, unknownValue); - return result == null - ? FailedConversion.from(new IllegalArgumentException("Not a valid choice: " + argument)) - : SuccessfulConversion.fromSingle(result); - } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java index c7a4b5bdd..4d431ebca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java @@ -31,9 +31,10 @@ import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + public class ExpandAmountConverter implements ArgumentConverter { public static void register(CommandManager commandManager) { @@ -53,9 +54,9 @@ public class ExpandAmountConverter implements ArgumentConverter { @Override public List getSuggestions(String input) { - return Stream.concat(Stream.of("vert"), integerConverter.getSuggestions(input).stream()) - .filter(x -> x.startsWith(input)) - .collect(Collectors.toList()); + return limitByPrefix(Stream.concat( + Stream.of("vert"), integerConverter.getSuggestions(input).stream() + ), input); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java index ed54327b1..15624d31b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryConverter.java @@ -19,54 +19,31 @@ package com.sk89q.worldedit.command.argument; +import com.google.common.collect.ImmutableSetMultimap; import com.sk89q.worldedit.regions.factory.CuboidRegionFactory; import com.sk89q.worldedit.regions.factory.CylinderRegionFactory; import com.sk89q.worldedit.regions.factory.RegionFactory; import com.sk89q.worldedit.regions.factory.SphereRegionFactory; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; import org.enginehub.piston.CommandManager; -import org.enginehub.piston.converter.ArgumentConverter; -import org.enginehub.piston.converter.ConversionResult; -import org.enginehub.piston.converter.FailedConversion; -import org.enginehub.piston.converter.SuccessfulConversion; -import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.converter.MultiKeyConverter; import org.enginehub.piston.inject.Key; -public class RegionFactoryConverter implements ArgumentConverter { +public class RegionFactoryConverter { public static void register(CommandManager commandManager) { - commandManager.registerConverter(Key.of(RegionFactory.class), new RegionFactoryConverter()); + commandManager.registerConverter(Key.of(RegionFactory.class), + MultiKeyConverter.builder( + ImmutableSetMultimap.builder() + .put(new CuboidRegionFactory(), "cuboid") + .put(new SphereRegionFactory(), "sphere") + .putAll(new CylinderRegionFactory(1), "cyl", "cylinder") + .build() + ) + .errorMessage(arg -> "Not a known region type: " + arg) + .build() + ); } private RegionFactoryConverter() { } - - @Override - public Component describeAcceptableArguments() { - return TextComponent.of("cuboid|sphere|cyl"); - } - - @Override - public ConversionResult convert(String argument, InjectedValueAccess context) { - try { - return SuccessfulConversion.fromSingle(parse(argument)); - } catch (Exception e) { - return FailedConversion.from(e); - } - } - - private RegionFactory parse(String argument) { - switch (argument) { - case "cuboid": - return new CuboidRegionFactory(); - case "sphere": - return new SphereRegionFactory(); - case "cyl": - case "cylinder": - return new CylinderRegionFactory(1); // TODO: Adjustable height - default: - throw new IllegalArgumentException("Not a known region type: " + argument); - } - } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java index 5e9d2ed66..7bafb86e9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.command.argument; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.registry.Registry; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -40,40 +41,52 @@ import org.enginehub.piston.converter.SuccessfulConversion; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; +import java.lang.reflect.Field; import java.util.List; -import java.util.stream.Collectors; + +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; public class RegistryConverter implements ArgumentConverter { + @SuppressWarnings("unchecked") public static void register(CommandManager commandManager) { - commandManager.registerConverter(Key.of(BlockType.class), - new RegistryConverter<>(BlockType.class, BlockType.REGISTRY)); - commandManager.registerConverter(Key.of(BlockCategory.class), - new RegistryConverter<>(BlockCategory.class, BlockCategory.REGISTRY)); - commandManager.registerConverter(Key.of(ItemType.class), - new RegistryConverter<>(ItemType.class, ItemType.REGISTRY)); - commandManager.registerConverter(Key.of(ItemCategory.class), - new RegistryConverter<>(ItemCategory.class, ItemCategory.REGISTRY)); - commandManager.registerConverter(Key.of(BiomeType.class), - new RegistryConverter<>(BiomeType.class, BiomeType.REGISTRY)); - commandManager.registerConverter(Key.of(EntityType.class), - new RegistryConverter<>(EntityType.class, EntityType.REGISTRY)); - commandManager.registerConverter(Key.of(FluidType.class), - new RegistryConverter<>(FluidType.class, FluidType.REGISTRY)); - commandManager.registerConverter(Key.of(FluidCategory.class), - new RegistryConverter<>(FluidCategory.class, FluidCategory.REGISTRY)); - commandManager.registerConverter(Key.of(GameMode.class), - new RegistryConverter<>(GameMode.class, GameMode.REGISTRY)); - commandManager.registerConverter(Key.of(WeatherType.class), - new RegistryConverter<>(WeatherType.class, WeatherType.REGISTRY)); + ImmutableList.of( + BlockType.class, + BlockCategory.class, + ItemType.class, + ItemCategory.class, + BiomeType.class, + EntityType.class, + FluidType.class, + FluidCategory.class, + GameMode.class, + WeatherType.class + ).stream() + .map(c -> (Class) c) + .forEach(registryType -> + commandManager.registerConverter(Key.of(registryType), from(registryType)) + ); + } + + @SuppressWarnings("unchecked") + private static RegistryConverter from(Class registryType) { + try { + Field registryField = registryType.getDeclaredField("REGISTRY"); + Registry registry = (Registry) registryField.get(null); + return new RegistryConverter<>(registryType, registry); + } catch (NoSuchFieldException e) { + throw new IllegalArgumentException("Not a registry-backed type: " + registryType.getName()); + } catch (IllegalAccessException e) { + throw new IllegalStateException("Registry field inaccessible on " + registryType.getName()); + } } private final Registry registry; private final TextComponent choices; - public RegistryConverter(Class clazz, Registry registry) { + private RegistryConverter(Class clazz, Registry registry) { this.registry = registry; - this.choices = TextComponent.of("any " + clazz.getSimpleName()); + this.choices = TextComponent.of("any " + registry.getName()); } @Override @@ -85,14 +98,13 @@ public class RegistryConverter implements ArgumentConverter { public ConversionResult convert(String argument, InjectedValueAccess injectedValueAccess) { V result = registry.get(argument); return result == null - ? FailedConversion.from(new IllegalArgumentException("Not a valid choice: " + argument)) + ? FailedConversion.from(new IllegalArgumentException( + "Not a valid " + registry.getName() + ": " + argument)) : SuccessfulConversion.fromSingle(result); } @Override public List getSuggestions(String input) { - return registry.keySet().stream() - .filter(string -> string.startsWith(input)) - .collect(Collectors.toList()); + return limitByPrefix(registry.keySet().stream(), input); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java index 7545068de..e7d7e9e58 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java @@ -39,6 +39,10 @@ public class Registry implements Iterable { this.name = name; } + public String getName() { + return name; + } + public @Nullable V get(final String key) { checkState(key.equals(key.toLowerCase()), "key must be lowercase"); return this.map.get(key); From 7188d27aaae7a2ad8fa53d0cd71b5be6db9f5e96 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 29 Apr 2019 22:11:15 -0700 Subject: [PATCH 096/366] Fix minor bugs in converters --- .../sk89q/worldedit/command/argument/BooleanConverter.java | 2 +- .../com/sk89q/worldedit/command/argument/VectorConverter.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java index 5d4ad5891..731a736b3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanConverter.java @@ -34,7 +34,7 @@ public class BooleanConverter { .putAll(true, "on", "t", "true", "y", "yes") .build() ) - .errorMessage(arg -> "Not a boolean value" + arg) + .errorMessage(arg -> "Not a boolean value: " + arg) .build() ); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java index bc91296d6..05ac95573 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/VectorConverter.java @@ -53,14 +53,14 @@ public class VectorConverter implements ArgumentConverter { commandManager.registerConverter(Key.of(Vector2.class), new VectorConverter<>( doubleConverter, - 3, + 2, cmps -> Vector2.at(cmps.get(0), cmps.get(1)), "vector with x and z" )); commandManager.registerConverter(Key.of(BlockVector3.class), new VectorConverter<>( intConverter, - 2, + 3, cmps -> BlockVector3.at(cmps.get(0), cmps.get(1), cmps.get(2)), "block vector with x, y, and z" )); From 1e51bebc46c4cc897a2d25e9dc7fdb2e3e140736 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 29 Apr 2019 22:15:52 -0700 Subject: [PATCH 097/366] Update to release Piston version --- worldedit-libs/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 610cd0752..00d33be30 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -89,7 +89,7 @@ configure(subprojects + project("core:ap")) { } project("core") { - def pistonVersion = '0.0.1-SNAPSHOT' + def pistonVersion = '0.1.0' dependencies { shade 'net.kyori:text-api:2.0.0' From b1c042b1962364d8fa164f2bc6d0f7926083e3d8 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 29 Apr 2019 22:40:32 -0700 Subject: [PATCH 098/366] Add checkstyle validation for formatting, fix issues --- config/checkstyle/checkstyle.xml | 8 ++++++++ .../java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java | 8 ++++---- .../java/com/sk89q/worldedit/command/BiomeCommands.java | 8 ++++---- .../java/com/sk89q/worldedit/command/GeneralCommands.java | 4 ++-- .../com/sk89q/worldedit/command/GenerationCommands.java | 4 ++-- .../java/com/sk89q/worldedit/command/ToolCommands.java | 8 ++++---- 6 files changed, 24 insertions(+), 16 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index a2d043d73..0fe76dff3 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -53,5 +53,13 @@ + + + + + + + + diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java index c74c8f382..eb0c2e382 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java @@ -90,7 +90,7 @@ public class MobSpawnerBlock extends BaseBlock { /** * Get the spawn delay. - * + * * @return the delay */ public short getDelay() { @@ -99,13 +99,13 @@ public class MobSpawnerBlock extends BaseBlock { /** * Set the spawn delay. - * + * * @param delay the delay to set */ public void setDelay(short delay) { this.delay = delay; } - + @Override public boolean hasNbtData() { return true; @@ -208,7 +208,7 @@ public class MobSpawnerBlock extends BaseBlock { this.spawnCount = spawnCountTag.getValue(); } if (spawnRangeTag != null) { - this.spawnRange =spawnRangeTag.getValue(); + this.spawnRange = spawnRangeTag.getValue(); } if (minSpawnDelayTag != null) { this.minSpawnDelay = minSpawnDelayTag.getValue(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index bb4788f9e..ef6e38981 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.command; -import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; - import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -59,6 +57,8 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; + /** * Implements biome-related commands such as "/biomelist". */ @@ -97,9 +97,9 @@ public class BiomeCommands { ) @CommandPermissions("worldedit.biome.info") public void biomeInfo(Player player, LocalSession session, - @Switch(name = 't', desc="Use the block you are looking at.") + @Switch(name = 't', desc = "Use the block you are looking at.") boolean useLineOfSight, - @Switch(name = 'p', desc="Use the block you are currently in.") + @Switch(name = 'p', desc = "Use the block you are currently in.") boolean usePosition) throws WorldEditException { BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 08e46addc..a84c3d1a0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -223,9 +223,9 @@ public class GeneralCommands { @Arg(desc = "Item query") String query, @Switch(name = 'b', desc = "Only search for blocks") - boolean blocksOnly, + boolean blocksOnly, @Switch(name = 'i', desc = "Only search for items") - boolean itemsOnly) throws WorldEditException { + boolean itemsOnly) throws WorldEditException { ItemType type = ItemTypes.get(query); if (type != null) { 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 646672d2f..5f5229aeb 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 @@ -227,8 +227,8 @@ public class GenerationCommands { } @Command( - name = "/hpyramid", - desc = "Generate a hollow pyramid" + name = "/hpyramid", + desc = "Generate a hollow pyramid" ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 2af2b8750..8242cfec9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -137,8 +137,8 @@ public class ToolCommands { } @Command( - name = "deltree", - desc = "Floating tree remover tool" + name = "deltree", + desc = "Floating tree remover tool" ) @CommandPermissions("worldedit.tool.deltree") public void deltree(Player player, LocalSession session) throws WorldEditException { @@ -150,8 +150,8 @@ public class ToolCommands { } @Command( - name = "farwand", - desc = "Wand at a distance tool" + name = "farwand", + desc = "Wand at a distance tool" ) @CommandPermissions("worldedit.tool.farwand") public void farwand(Player player, LocalSession session) throws WorldEditException { From 7c1764548d5a0e92eb1d9e775122b9c9d04635d1 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 30 Apr 2019 13:53:14 -0700 Subject: [PATCH 099/366] Deprecate old system, still in use by WG/CB --- .../util/CommandsManagerRegistration.java | 2 ++ .../bukkit/util/DynamicPluginCommand.java | 1 + .../util/DynamicPluginCommandHelpTopic.java | 1 + .../util/commands/CommandsManager.java | 1 + .../minecraft/util/commands/package-info.java | 24 +++++++++++++++++++ 5 files changed, 29 insertions(+) create mode 100644 worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/package-info.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java index 5f8bfbc8c..7e64bf319 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java @@ -31,6 +31,8 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +@Deprecated +@SuppressWarnings("deprecation") public class CommandsManagerRegistration extends CommandRegistration { protected CommandsManager commands; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommand.java b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommand.java index 479681c6b..9f1912587 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommand.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommand.java @@ -35,6 +35,7 @@ import java.util.List; /** * An implementation of a dynamically registered {@link org.bukkit.command.Command} attached to a plugin */ +@SuppressWarnings("deprecation") public class DynamicPluginCommand extends org.bukkit.command.Command implements PluginIdentifiableCommand { protected final CommandExecutor owner; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java index 6f4cec526..7635d174e 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/bukkit/util/DynamicPluginCommandHelpTopic.java @@ -30,6 +30,7 @@ import org.bukkit.help.HelpTopicFactory; import java.util.Map; +@SuppressWarnings("deprecation") public class DynamicPluginCommandHelpTopic extends HelpTopic { private final DynamicPluginCommand cmd; diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java index df3b0806b..5263d3aba 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java @@ -60,6 +60,7 @@ import java.util.Set; * @param command sender class */ @SuppressWarnings("ProtectedField") +@Deprecated public abstract class CommandsManager { protected static final Logger logger = diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/package-info.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/package-info.java new file mode 100644 index 000000000..8dd9c94ff --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/package-info.java @@ -0,0 +1,24 @@ +/* + * 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 . + */ + +/** + * This package contains the old command system. It is no longer in use. Please switch + * to Piston, Intake, ACF, or similar systems. + */ +package com.sk89q.minecraft.util.commands; \ No newline at end of file From 743d7f08ab3bc3ca2362fb64283ee6fd2310a5cb Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 30 Apr 2019 14:59:45 -0700 Subject: [PATCH 100/366] Purge intake-like command system --- .../command/argument/BooleanFlag.java | 63 --- .../command/argument/NumberParser.java | 85 ---- .../command/argument/RegionFactoryParser.java | 81 --- .../command/argument/StringParser.java | 80 --- .../command/argument/TreeGeneratorParser.java | 106 ---- .../command/composition/DeformCommand.java | 84 --- .../command/composition/SelectionCommand.java | 115 ----- .../composition/ShapedBrushCommand.java | 103 ---- .../extension/platform/Platform.java | 4 +- .../command/UserCommandCompleter.java | 72 --- .../internal/command/WorldEditBinding.java | 331 ------------ .../util/command/CommandCallable.java | 59 --- .../util/command/CommandCompleter.java | 42 -- .../util/command/CommandMapping.java | 55 -- .../worldedit/util/command/Description.java | 70 --- .../worldedit/util/command/Dispatcher.java | 86 ---- .../util/command/InvalidUsageException.java | 107 ---- .../command/MissingParameterException.java | 29 -- .../worldedit/util/command/NullCompleter.java | 38 -- .../worldedit/util/command/Parameter.java | 66 --- .../util/command/PrimaryAliasComparator.java | 60 --- .../util/command/SimpleCommandMapping.java | 72 --- .../util/command/SimpleDescription.java | 135 ----- .../util/command/SimpleDispatcher.java | 189 ------- .../util/command/SimpleParameter.java | 134 ----- .../command/UnconsumedParameterException.java | 40 -- .../command/argument/ArgumentException.java | 39 -- .../argument/ArgumentParseException.java | 39 -- .../util/command/argument/ArgumentUtils.java | 45 -- .../util/command/argument/CommandArgs.java | 162 ------ .../argument/MissingArgumentException.java | 39 -- .../argument/UnusedArgumentsException.java | 39 -- .../command/binding/PrimitiveBindings.java | 294 ----------- .../worldedit/util/command/binding/Range.java | 50 -- .../command/binding/StandardBindings.java | 46 -- .../util/command/binding/Switch.java | 44 -- .../worldedit/util/command/binding/Text.java | 41 -- .../util/command/binding/Validate.java | 45 -- .../command/composition/BranchingCommand.java | 111 ---- .../command/composition/CommandExecutor.java | 41 -- .../util/command/composition/FlagParser.java | 196 ------- .../composition/LegacyCommandAdapter.java | 87 ---- .../command/composition/ParameterCommand.java | 79 --- .../command/composition/ProvidedValue.java | 69 --- .../command/composition/SimpleCommand.java | 54 -- .../util/command/fluent/CommandGraph.java | 84 --- .../util/command/fluent/DispatcherNode.java | 139 ----- .../parametric/AbstractInvokeListener.java | 36 -- .../command/parametric/ArgumentStack.java | 78 --- .../util/command/parametric/Binding.java | 93 ---- .../command/parametric/BindingBehavior.java | 52 -- .../command/parametric/BindingHelper.java | 224 -------- .../util/command/parametric/BindingMatch.java | 71 --- .../parametric/ContextArgumentStack.java | 178 ------- .../parametric/ExceptionConverter.java | 17 +- .../command/parametric/InvokeHandler.java | 82 --- .../command/parametric/InvokeListener.java | 58 --- .../parametric/LegacyCommandsHandler.java | 97 ---- .../util/command/parametric/Optional.java | 41 -- .../command/parametric/ParameterData.java | 194 ------- .../parametric/ParameterException.java | 43 -- .../command/parametric/ParametricBuilder.java | 230 --------- .../parametric/ParametricCallable.java | 479 ------------------ .../parametric/ParametricException.java | 44 -- .../parametric/StringArgumentStack.java | 128 ----- .../worldedit/sponge/SpongePlatform.java | 5 +- 66 files changed, 10 insertions(+), 6189 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanFlag.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryParser.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringParser.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/TreeGeneratorParser.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/DeformCommand.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/UserCommandCompleter.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandCompleter.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandMapping.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Description.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Dispatcher.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/InvalidUsageException.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/MissingParameterException.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/NullCompleter.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Parameter.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/PrimaryAliasComparator.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleCommandMapping.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleParameter.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/UnconsumedParameterException.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentException.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentParseException.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/CommandArgs.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/MissingArgumentException.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/UnusedArgumentsException.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/PrimitiveBindings.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Range.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/StandardBindings.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Switch.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Text.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Validate.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/CommandExecutor.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/FlagParser.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/LegacyCommandAdapter.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ParameterCommand.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ProvidedValue.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/SimpleCommand.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/fluent/CommandGraph.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/AbstractInvokeListener.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ArgumentStack.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/Binding.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingBehavior.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingHelper.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingMatch.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ContextArgumentStack.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/InvokeHandler.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/InvokeListener.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/LegacyCommandsHandler.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/Optional.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterData.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterException.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricException.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/StringArgumentStack.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanFlag.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanFlag.java deleted file mode 100644 index 3e849a099..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/BooleanFlag.java +++ /dev/null @@ -1,63 +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 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.command.argument; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.composition.CommandExecutor; - -import java.util.Collections; -import java.util.List; - -public class BooleanFlag implements CommandExecutor { - - private final String description; - - public BooleanFlag(String description) { - this.description = description; - } - - @Override - public Boolean call(CommandArgs args, CommandLocals locals) throws CommandException { - return true; - } - - @Override - public List getSuggestions(CommandArgs args, CommandLocals locals) { - return Collections.emptyList(); - } - - @Override - public String getUsage() { - return ""; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public boolean testPermission(CommandLocals locals) { - return true; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java deleted file mode 100644 index dcb06b4f9..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/NumberParser.java +++ /dev/null @@ -1,85 +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 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.command.argument; - -import com.google.common.collect.Lists; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.argument.MissingArgumentException; -import com.sk89q.worldedit.util.command.composition.CommandExecutor; - -import java.util.Collections; -import java.util.List; - -import javax.annotation.Nullable; - -public class NumberParser implements CommandExecutor { - - private final String name; - private final String description; - private final @Nullable String defaultSuggestion; - - public NumberParser(String name, String description) { - this(name, description, null); - } - - public NumberParser(String name, String description, @Nullable String defaultSuggestion) { - this.name = name; - this.description = description; - this.defaultSuggestion = defaultSuggestion; - } - - @Override - public Number call(CommandArgs args, CommandLocals locals) throws CommandException { - try { - String next = args.next(); - try { - return Double.parseDouble(next); - } catch (NumberFormatException ignored) { - throw new CommandException("The value for <" + name + "> should be a number. '" + next + "' is not a number."); - } - } catch (MissingArgumentException e) { - throw new CommandException("Missing value for <" + name + "> (try a number)."); - } - } - - @Override - public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { - String value = args.next(); - return value.isEmpty() && defaultSuggestion != null ? Lists.newArrayList(defaultSuggestion) : Collections.emptyList(); - } - - @Override - public String getUsage() { - return "<" + name + ">"; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public boolean testPermission(CommandLocals locals) { - return true; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryParser.java deleted file mode 100644 index 9ec0ce101..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegionFactoryParser.java +++ /dev/null @@ -1,81 +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 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.command.argument; - -import com.google.common.collect.Lists; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.regions.factory.CuboidRegionFactory; -import com.sk89q.worldedit.regions.factory.CylinderRegionFactory; -import com.sk89q.worldedit.regions.factory.RegionFactory; -import com.sk89q.worldedit.regions.factory.SphereRegionFactory; -import com.sk89q.worldedit.util.command.argument.ArgumentUtils; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.argument.MissingArgumentException; -import com.sk89q.worldedit.util.command.composition.CommandExecutor; - -import java.util.List; - -public class RegionFactoryParser implements CommandExecutor { - - @Override - public RegionFactory call(CommandArgs args, CommandLocals locals) throws CommandException { - try { - String type = args.next(); - - switch (type) { - case "cuboid": - return new CuboidRegionFactory(); - case "sphere": - return new SphereRegionFactory(); - case "cyl": - case "cylinder": - return new CylinderRegionFactory(1); // TODO: Adjustable height - - default: - throw new CommandException("Unknown shape type: " + type + " (try one of " + getUsage() + ")"); - } - } catch (MissingArgumentException e) { - throw new CommandException("Missing shape type (try one of " + getUsage() + ")"); - - } - } - - @Override - public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { - return ArgumentUtils.getMatchingSuggestions(Lists.newArrayList("cuboid", "sphere", "cyl"), args.next()); - } - - @Override - public String getUsage() { - return "(cuboid | sphere | cyl)"; - } - - @Override - public String getDescription() { - return "Defines a region"; - } - - @Override - public boolean testPermission(CommandLocals locals) { - return true; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringParser.java deleted file mode 100644 index 30c02381f..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/StringParser.java +++ /dev/null @@ -1,80 +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 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.command.argument; - -import com.google.common.collect.Lists; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.argument.MissingArgumentException; -import com.sk89q.worldedit.util.command.composition.CommandExecutor; - -import java.util.Collections; -import java.util.List; - -import javax.annotation.Nullable; - -public class StringParser implements CommandExecutor { - - private final String name; - private final String description; - private final @Nullable String defaultSuggestion; - - public StringParser(String name, String description) { - this(name, description, null); - } - - public StringParser(String name, String description, @Nullable String defaultSuggestion) { - this.name = name; - this.description = description; - this.defaultSuggestion = defaultSuggestion; - } - - @Override - public String call(CommandArgs args, CommandLocals locals) throws CommandException { - try { - return args.next(); - } catch (MissingArgumentException e) { - throw new CommandException("Missing value for <" + name + ">."); - } - } - - @Override - public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { - String value = args.next(); - return value.isEmpty() && defaultSuggestion != null ? Lists.newArrayList(defaultSuggestion) : Collections.emptyList(); - } - - @Override - public String getUsage() { - return "<" + name + ">"; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public boolean testPermission(CommandLocals locals) { - return true; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/TreeGeneratorParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/TreeGeneratorParser.java deleted file mode 100644 index 3d3f73d6b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/TreeGeneratorParser.java +++ /dev/null @@ -1,106 +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 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.command.argument; - -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.function.Contextual; -import com.sk89q.worldedit.function.EditContext; -import com.sk89q.worldedit.function.generator.ForestGenerator; -import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.TreeGenerator.TreeType; -import com.sk89q.worldedit.util.command.argument.ArgumentUtils; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.argument.MissingArgumentException; -import com.sk89q.worldedit.util.command.composition.CommandExecutor; - -import java.util.Arrays; -import java.util.List; - -public class TreeGeneratorParser implements CommandExecutor> { - - private final String name; - - public TreeGeneratorParser(String name) { - this.name = name; - } - - private String getOptionsList() { - return Joiner.on(" | ").join(Arrays.asList(TreeType.values())); - } - - @Override - public Contextual call(CommandArgs args, CommandLocals locals) throws CommandException { - try { - String input = args.next(); - TreeType type = TreeGenerator.lookup(input); - if (type != null) { - return new GeneratorFactory(type); - } else { - throw new CommandException("Unknown value for <" + name + "> (try one of " + getOptionsList() + ")."); - } - } catch (MissingArgumentException e) { - throw new CommandException("Missing value for <" + name + "> (try one of " + getOptionsList() + ")."); - } - } - - @Override - public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { - String s = args.next(); - return s.isEmpty() ? Lists.newArrayList(TreeType.getPrimaryAliases()) : ArgumentUtils.getMatchingSuggestions(TreeType.getAliases(), s); - } - - @Override - public String getUsage() { - return "<" + name + ">"; - } - - @Override - public String getDescription() { - return "Choose a tree generator"; - } - - @Override - public boolean testPermission(CommandLocals locals) { - return true; - } - - private static final class GeneratorFactory implements Contextual { - private final TreeType type; - - private GeneratorFactory(TreeType type) { - this.type = type; - } - - @Override - public ForestGenerator createFromContext(EditContext input) { - return new ForestGenerator((EditSession) input.getDestination(), type); - } - - @Override - public String toString() { - return "tree of type " + type; - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/DeformCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/DeformCommand.java deleted file mode 100644 index cae499dce..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/DeformCommand.java +++ /dev/null @@ -1,84 +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 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.command.composition; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.minecraft.util.commands.WrappedCommandException; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.command.argument.BooleanFlag; -import com.sk89q.worldedit.command.argument.StringParser; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.function.Contextual; -import com.sk89q.worldedit.function.factory.Deform; -import com.sk89q.worldedit.function.factory.Deform.Mode; -import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.composition.FlagParser.Flag; -import com.sk89q.worldedit.util.command.composition.FlagParser.FlagData; -import com.sk89q.worldedit.util.command.composition.SimpleCommand; - -public class DeformCommand extends SimpleCommand> { - - private final Flag rawCoordsFlag = addFlag('r', new BooleanFlag("Raw coords mode")); - private final Flag offsetFlag = addFlag('o', new BooleanFlag("Offset mode")); - private final StringParser expressionParser = addParameter(new StringParser("expression", "Expression to apply", "y-=0.2")); - - @Override - public Deform call(CommandArgs args, CommandLocals locals) throws CommandException { - FlagData flagData = getFlagParser().call(args, locals); - String expression = expressionParser.call(args, locals); - boolean rawCoords = rawCoordsFlag.get(flagData, false); - boolean offset = offsetFlag.get(flagData, false); - - Deform deform = new Deform(expression); - - if (rawCoords) { - deform.setMode(Mode.RAW_COORD); - } else if (offset) { - deform.setMode(Mode.OFFSET); - Player player = (Player) locals.get(Actor.class); - LocalSession session = WorldEdit.getInstance().getSessionManager().get(locals.get(Actor.class)); - try { - deform.setOffset(session.getPlacementPosition(player).toVector3()); - } catch (IncompleteRegionException e) { - throw new WrappedCommandException(e); - } - } else { - deform.setMode(Mode.UNIT_CUBE); - } - - return deform; - } - - @Override - public String getDescription() { - return "Apply math expression to area"; - } - - @Override - protected boolean testPermission0(CommandLocals locals) { - return true; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java deleted file mode 100644 index c0f93463c..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java +++ /dev/null @@ -1,115 +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 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.command.composition; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.minecraft.util.commands.CommandPermissionsException; -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.function.Contextual; -import com.sk89q.worldedit.function.EditContext; -import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.composition.CommandExecutor; -import com.sk89q.worldedit.util.command.composition.SimpleCommand; - -import java.util.List; - -public class SelectionCommand extends SimpleCommand { - - private final CommandExecutor> delegate; - private final String permission; - - public SelectionCommand(CommandExecutor> delegate, String permission) { - checkNotNull(delegate, "delegate"); - checkNotNull(permission, "permission"); - this.delegate = delegate; - this.permission = permission; - addParameter(delegate); - } - - @Override - public Operation call(CommandArgs args, CommandLocals locals) throws CommandException { - if (!testPermission(locals)) { - throw new CommandPermissionsException(); - } - - Contextual operationFactory = delegate.call(args, locals); - - Actor actor = locals.get(Actor.class); - if (actor instanceof Player) { - try { - Player player = (Player) actor; - LocalSession session = WorldEdit.getInstance().getSessionManager().get(player); - Region selection = session.getSelection(player.getWorld()); - - EditSession editSession = session.createEditSession(player); - editSession.enableStandardMode(); - locals.put(EditSession.class, editSession); - session.tellVersion(player); - - EditContext editContext = new EditContext(); - editContext.setDestination(locals.get(EditSession.class)); - editContext.setRegion(selection); - editContext.setSession(session); - - Operation operation = operationFactory.createFromContext(editContext); - Operations.completeBlindly(operation); - - List messages = Lists.newArrayList(); - operation.addStatusMessages(messages); - if (messages.isEmpty()) { - actor.print("Operation completed."); - } else { - actor.print("Operation completed (" + Joiner.on(", ").join(messages) + ")."); - } - - return operation; - } catch (IncompleteRegionException e) { - WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter().convert(e); - return null; - } - } else { - throw new CommandException("This command can only be used by players."); - } - } - - @Override - public String getDescription() { - return delegate.getDescription(); - } - - @Override - protected boolean testPermission0(CommandLocals locals) { - return locals.get(Actor.class).hasPermission(permission); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java deleted file mode 100644 index 911c4080e..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/composition/ShapedBrushCommand.java +++ /dev/null @@ -1,103 +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 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.command.composition; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.minecraft.util.commands.CommandPermissionsException; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.MaxBrushRadiusException; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.command.argument.NumberParser; -import com.sk89q.worldedit.command.argument.RegionFactoryParser; -import com.sk89q.worldedit.command.tool.BrushTool; -import com.sk89q.worldedit.command.tool.InvalidToolBindException; -import com.sk89q.worldedit.command.tool.brush.OperationFactoryBrush; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.function.Contextual; -import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.regions.factory.RegionFactory; -import com.sk89q.worldedit.util.HandSide; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.composition.CommandExecutor; -import com.sk89q.worldedit.util.command.composition.SimpleCommand; - -public class ShapedBrushCommand extends SimpleCommand { - - private final CommandExecutor> delegate; - private final String permission; - - private final RegionFactoryParser regionFactoryParser = addParameter(new RegionFactoryParser()); - private final NumberParser radiusCommand = addParameter(new NumberParser("size", "The size of the brush", "5")); - - public ShapedBrushCommand(CommandExecutor> delegate, String permission) { - checkNotNull(delegate, "delegate"); - this.permission = permission; - this.delegate = delegate; - addParameter(delegate); - } - - @Override - public Object call(CommandArgs args, CommandLocals locals) throws CommandException { - if (!testPermission(locals)) { - throw new CommandPermissionsException(); - } - - RegionFactory regionFactory = regionFactoryParser.call(args, locals); - int radius = radiusCommand.call(args, locals).intValue(); - Contextual factory = delegate.call(args, locals); - - Player player = (Player) locals.get(Actor.class); - LocalSession session = WorldEdit.getInstance().getSessionManager().get(player); - - try { - WorldEdit.getInstance().checkMaxBrushRadius(radius); - BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); - tool.setSize(radius); - tool.setFill(null); - tool.setBrush(new OperationFactoryBrush(factory, regionFactory, session), permission); - } catch (MaxBrushRadiusException | InvalidToolBindException e) { - WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter().convert(e); - } - - player.print("Set brush to " + factory); - - return true; - } - - @Override - public String getDescription() { - return delegate.getDescription(); - } - - @Override - public boolean testPermission0(CommandLocals locals) { - Actor sender = locals.get(Actor.class); - if (sender == null) { - throw new RuntimeException("Uh oh! No 'Actor' specified so that we can check permissions"); - } else { - return sender.hasPermission(permission); - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index 79fac2c57..1a25497f5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -21,16 +21,14 @@ package com.sk89q.worldedit.extension.platform; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; import org.enginehub.piston.CommandManager; +import javax.annotation.Nullable; import java.util.List; import java.util.Map; -import javax.annotation.Nullable; - /** * Represents a platform that WorldEdit has been implemented for. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/UserCommandCompleter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/UserCommandCompleter.java deleted file mode 100644 index a93363295..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/UserCommandCompleter.java +++ /dev/null @@ -1,72 +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 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.internal.command; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.extension.platform.MultiUserPlatform; -import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.extension.platform.PlatformManager; -import com.sk89q.worldedit.util.command.CommandCompleter; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * Provides the names of connected users as suggestions. - */ -public class UserCommandCompleter implements CommandCompleter { - - private final PlatformManager platformManager; - - /** - * Create a new instance. - * - * @param platformManager the platform manager - */ - public UserCommandCompleter(PlatformManager platformManager) { - checkNotNull(platformManager); - this.platformManager = platformManager; - } - - @Override - public List getSuggestions(String arguments, CommandLocals locals) throws CommandException { - Platform platform = platformManager.queryCapability(Capability.USER_COMMANDS); - if (platform instanceof MultiUserPlatform) { - List suggestions = new ArrayList<>(); - Collection users = ((MultiUserPlatform) platform).getConnectedUsers(); - for (Actor user : users) { - if (user.getName().toLowerCase().startsWith(arguments.toLowerCase().trim())) { - suggestions.add(user.getName()); - } - } - return suggestions; - } else { - return Collections.emptyList(); - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java deleted file mode 100644 index b13924e72..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditBinding.java +++ /dev/null @@ -1,331 +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 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.internal.command; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.IncompleteRegionException; -import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.UnknownDirectionException; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.input.NoMatchException; -import com.sk89q.worldedit.extension.input.ParserContext; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.internal.annotation.Direction; -import com.sk89q.worldedit.internal.annotation.Selection; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.TreeGenerator.TreeType; -import com.sk89q.worldedit.util.command.parametric.ArgumentStack; -import com.sk89q.worldedit.util.command.parametric.BindingBehavior; -import com.sk89q.worldedit.util.command.parametric.BindingHelper; -import com.sk89q.worldedit.util.command.parametric.BindingMatch; -import com.sk89q.worldedit.util.command.parametric.ParameterException; -import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.Biomes; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; -import com.sk89q.worldedit.world.registry.BiomeRegistry; - -import java.util.Collection; - -/** - * Binds standard WorldEdit classes such as {@link Player} and {@link LocalSession}. - */ -public class WorldEditBinding extends BindingHelper { - - private final WorldEdit worldEdit; - - /** - * Create a new instance. - * - * @param worldEdit the WorldEdit instance to bind to - */ - public WorldEditBinding(WorldEdit worldEdit) { - this.worldEdit = worldEdit; - } - - /** - * Gets a selection from a {@link ArgumentStack}. - * - * @param context the context - * @param selection the annotation - * @return a selection - * @throws IncompleteRegionException if no selection is available - * @throws ParameterException on other error - */ - @BindingMatch(classifier = Selection.class, - type = Region.class, - behavior = BindingBehavior.PROVIDES) - public Object getSelection(ArgumentStack context, @SuppressWarnings("unused") Selection selection) throws IncompleteRegionException, ParameterException { - Player sender = getPlayer(context); - LocalSession session = worldEdit.getSessionManager().get(sender); - return session.getSelection(sender.getWorld()); - } - - /** - * Gets an {@link EditSession} from a {@link ArgumentStack}. - * - * @param context the context - * @return an edit session - * @throws ParameterException on other error - */ - @BindingMatch(type = EditSession.class, - behavior = BindingBehavior.PROVIDES) - public EditSession getEditSession(ArgumentStack context) throws ParameterException { - Player sender = getPlayer(context); - LocalSession session = worldEdit.getSessionManager().get(sender); - EditSession editSession = session.createEditSession(sender); - editSession.enableStandardMode(); - context.getContext().getLocals().put(EditSession.class, editSession); - session.tellVersion(sender); - return editSession; - } - - /** - * Gets an {@link LocalSession} from a {@link ArgumentStack}. - * - * @param context the context - * @return a local session - * @throws ParameterException on error - */ - @BindingMatch(type = LocalSession.class, - behavior = BindingBehavior.PROVIDES) - public LocalSession getLocalSession(ArgumentStack context) throws ParameterException { - Player sender = getPlayer(context); - return worldEdit.getSessionManager().get(sender); - } - - /** - * Gets an {@link Actor} from a {@link ArgumentStack}. - * - * @param context the context - * @return a local player - * @throws ParameterException on error - */ - @BindingMatch(type = Actor.class, - behavior = BindingBehavior.PROVIDES) - public Actor getActor(ArgumentStack context) throws ParameterException { - Actor sender = context.getContext().getLocals().get(Actor.class); - if (sender == null) { - throw new ParameterException("Missing 'Actor'"); - } else { - return sender; - } - } - - /** - * Gets an {@link Player} from a {@link ArgumentStack}. - * - * @param context the context - * @return a local player - * @throws ParameterException on error - */ - @BindingMatch(type = Player.class, - behavior = BindingBehavior.PROVIDES) - public Player getPlayer(ArgumentStack context) throws ParameterException { - Actor sender = context.getContext().getLocals().get(Actor.class); - if (sender == null) { - throw new ParameterException("No player to get a session for"); - } else if (sender instanceof Player) { - return (Player) sender; - } else { - throw new ParameterException("Caller is not a player"); - } - } - - /** - * Gets an {@link BaseBlock} from a {@link ArgumentStack}. - * - * @param context the context - * @return a pattern - * @throws ParameterException on error - * @throws WorldEditException on error - */ - @BindingMatch(type = {BaseBlock.class, BlockState.class, BlockStateHolder.class}, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1) - public BaseBlock getBaseBlock(ArgumentStack context) throws ParameterException, WorldEditException { - Actor actor = context.getContext().getLocals().get(Actor.class); - ParserContext parserContext = new ParserContext(); - parserContext.setActor(context.getContext().getLocals().get(Actor.class)); - if (actor instanceof Entity) { - Extent extent = ((Entity) actor).getExtent(); - if (extent instanceof World) { - parserContext.setWorld((World) extent); - } - } - parserContext.setSession(worldEdit.getSessionManager().get(actor)); - try { - return worldEdit.getBlockFactory().parseFromInput(context.next(), parserContext); - } catch (NoMatchException e) { - throw new ParameterException(e.getMessage(), e); - } - } - - /** - * Gets an {@link Pattern} from a {@link ArgumentStack}. - * - * @param context the context - * @return a pattern - * @throws ParameterException on error - * @throws WorldEditException on error - */ - @BindingMatch(type = Pattern.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1) - public Pattern getPattern(ArgumentStack context) throws ParameterException, WorldEditException { - Actor actor = context.getContext().getLocals().get(Actor.class); - ParserContext parserContext = new ParserContext(); - parserContext.setActor(context.getContext().getLocals().get(Actor.class)); - if (actor instanceof Entity) { - Extent extent = ((Entity) actor).getExtent(); - if (extent instanceof World) { - parserContext.setWorld((World) extent); - } - } - parserContext.setSession(worldEdit.getSessionManager().get(actor)); - try { - return worldEdit.getPatternFactory().parseFromInput(context.next(), parserContext); - } catch (NoMatchException e) { - throw new ParameterException(e.getMessage(), e); - } - } - - /** - * Gets an {@link Mask} from a {@link ArgumentStack}. - * - * @param context the context - * @return a pattern - * @throws ParameterException on error - * @throws WorldEditException on error - */ - @BindingMatch(type = Mask.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1) - public Mask getMask(ArgumentStack context) throws ParameterException, WorldEditException { - Actor actor = context.getContext().getLocals().get(Actor.class); - ParserContext parserContext = new ParserContext(); - parserContext.setActor(context.getContext().getLocals().get(Actor.class)); - if (actor instanceof Entity) { - Extent extent = ((Entity) actor).getExtent(); - if (extent instanceof World) { - parserContext.setWorld((World) extent); - } - } - parserContext.setSession(worldEdit.getSessionManager().get(actor)); - try { - return worldEdit.getMaskFactory().parseFromInput(context.next(), parserContext); - } catch (NoMatchException e) { - throw new ParameterException(e.getMessage(), e); - } - } - - /** - * Get a direction from the player. - * - * @param context the context - * @param direction the direction annotation - * @return a pattern - * @throws ParameterException on error - * @throws UnknownDirectionException on an unknown direction - */ - @BindingMatch(classifier = Direction.class, - type = BlockVector3.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1) - public BlockVector3 getDirection(ArgumentStack context, Direction direction) - throws ParameterException, UnknownDirectionException { - Player sender = getPlayer(context); - if (direction.includeDiagonals()) { - return worldEdit.getDiagonalDirection(sender, context.next()); - } else { - return worldEdit.getDirection(sender, context.next()); - } - } - - /** - * Gets an {@link TreeType} from a {@link ArgumentStack}. - * - * @param context the context - * @return a pattern - * @throws ParameterException on error - * @throws WorldEditException on error - */ - @BindingMatch(type = TreeType.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1) - public TreeType getTreeType(ArgumentStack context) throws ParameterException, WorldEditException { - String input = context.next(); - if (input != null) { - TreeType type = TreeGenerator.lookup(input); - if (type != null) { - return type; - } else { - throw new ParameterException( - String.format("Can't recognize tree type '%s' -- choose from: %s", input, - TreeType.getPrimaryAliases())); - } - } else { - return TreeType.TREE; - } - } - - /** - * Gets an {@link BiomeType} from a {@link ArgumentStack}. - * - * @param context the context - * @return a pattern - * @throws ParameterException on error - * @throws WorldEditException on error - */ - @BindingMatch(type = BiomeType.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1) - public BiomeType getBiomeType(ArgumentStack context) throws ParameterException, WorldEditException { - String input = context.next(); - if (input != null) { - BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() - .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); - Collection knownBiomes = BiomeType.REGISTRY.values(); - BiomeType biome = Biomes.findBiomeByName(knownBiomes, input, biomeRegistry); - if (biome != null) { - return biome; - } else { - throw new ParameterException( - String.format("Can't recognize biome type '%s' -- use /biomelist to list available types", input)); - } - } else { - throw new ParameterException( - "This command takes a 'default' biome if one is not set, except there is no particular " + - "biome that should be 'default', so the command should not be taking a default biome"); - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java deleted file mode 100644 index a40660d19..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java +++ /dev/null @@ -1,59 +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 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.util.command; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; - -/** - * A command that can be executed. - */ -public interface CommandCallable extends CommandCompleter { - - /** - * Execute the correct command based on the input. - * - *

The implementing class must perform the necessary permission - * checks.

- * - * @param arguments the arguments - * @param locals the locals - * @param parentCommands a list of parent commands, with the first most entry being the top-level command - * @return the called command, or null if there was no command found - * @throws CommandException thrown on a command error - */ - Object call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException; - - /** - * Get an object describing this command. - * - * @return the command description - */ - Description getDescription(); - - /** - * Test whether this command can be executed with the given context. - * - * @param locals the locals - * @return true if execution is permitted - */ - boolean testPermission(CommandLocals locals); - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandCompleter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandCompleter.java deleted file mode 100644 index 19bf47d60..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandCompleter.java +++ /dev/null @@ -1,42 +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 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.util.command; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; - -import java.util.List; - -/** - * Provides a method that can provide tab completion for commands. - */ -public interface CommandCompleter { - - /** - * Get a list of suggestions based on input. - * - * @param arguments the arguments entered up to this point - * @param locals the locals - * @return a list of suggestions - * @throws CommandException thrown if there was a parsing error - */ - List getSuggestions(String arguments, CommandLocals locals) throws CommandException; - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandMapping.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandMapping.java deleted file mode 100644 index 093850728..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandMapping.java +++ /dev/null @@ -1,55 +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 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.util.command; - -/** - * Provides information about a mapping between a command and its aliases. - */ -public interface CommandMapping { - - /** - * Get the primary alias. - * - * @return the primary alias - */ - String getPrimaryAlias(); - - /** - * Get a list of all aliases. - * - * @return aliases - */ - String[] getAllAliases(); - - /** - * Get the callable - * - * @return the callable - */ - CommandCallable getCallable(); - - /** - * Get the {@link Description} form the callable. - * - * @return the description - */ - Description getDescription(); - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Description.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Description.java deleted file mode 100644 index 89c8af2a4..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Description.java +++ /dev/null @@ -1,70 +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 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.util.command; - -import java.util.List; - -/** - * A description of a command. - */ -public interface Description { - - /** - * Get the list of parameters for this command. - * - * @return a list of parameters - */ - List getParameters(); - - /** - * Get a short one-line description of this command. - * - * @return a description, or null if no description is available - */ - String getDescription(); - - /** - * Get a longer help text about this command. - * - * @return a help text, or null if no help is available - */ - String getHelp(); - - /** - * Get the usage string of this command. - * - *

A usage string may look like - * {@code [-w <world>] <var1> <var2>}.

- * - * @return a usage string - */ - String getUsage(); - - /** - * Get a list of permissions that the player may have to have permission. - * - *

Permission data may or may not be available. This is only useful as a - * potential hint.

- * - * @return the list of permissions - */ - List getPermissions(); - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Dispatcher.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Dispatcher.java deleted file mode 100644 index a7f1405f8..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Dispatcher.java +++ /dev/null @@ -1,86 +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 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.util.command; - -import java.util.Collection; -import java.util.Set; - -import javax.annotation.Nullable; - -/** - * Executes a command based on user input. - */ -public interface Dispatcher extends CommandCallable { - - /** - * Register a command with this dispatcher. - * - * @param callable the command executor - * @param alias a list of aliases, where the first alias is the primary name - */ - void registerCommand(CommandCallable callable, String... alias); - - /** - * Get a list of commands. Each command, regardless of how many aliases - * it may have, will only appear once in the returned set. - * - *

The returned collection cannot be modified.

- * - * @return a list of registrations - */ - Set getCommands(); - - /** - * Get a list of primary aliases. - * - *

The returned collection cannot be modified.

- * - * @return a list of aliases - */ - Collection getPrimaryAliases(); - - /** - * Get a list of all the command aliases, which includes the primary alias. - * - *

A command may have more than one alias assigned to it. The returned - * collection cannot be modified.

- * - * @return a list of aliases - */ - Collection getAliases(); - - /** - * Get the {@link CommandCallable} associated with an alias. Returns - * null if no command is named by the given alias. - * - * @param alias the alias - * @return the command mapping (null if not found) - */ - @Nullable CommandMapping get(String alias); - - /** - * Returns whether the dispatcher contains a registered command for the given alias. - * - * @param alias the alias - * @return true if a registered command exists - */ - boolean contains(String alias); - -} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/InvalidUsageException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/InvalidUsageException.java deleted file mode 100644 index 0ffbc4c1e..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/InvalidUsageException.java +++ /dev/null @@ -1,107 +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 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.util.command; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.minecraft.util.commands.CommandException; - -import javax.annotation.Nullable; - -/** - * Thrown when a command is not used properly. - * - *

When handling this exception, print the error message if it is not null. - * Print a one line help instruction unless {@link #isFullHelpSuggested()} - * is true, which, in that case, the full help of the command should be - * shown.

- * - *

If no error message is set and full help is not to be shown, then a generic - * "you used this command incorrectly" message should be shown.

- */ -public class InvalidUsageException extends CommandException { - - private final CommandCallable command; - private final boolean fullHelpSuggested; - - /** - * Create a new instance with no error message and with no suggestion - * that full and complete help for the command should be shown. This will - * result in a generic error message. - * - * @param command the command - */ - public InvalidUsageException(CommandCallable command) { - this(null, command); - } - - /** - * Create a new instance with a message and with no suggestion - * that full and complete help for the command should be shown. - * - * @param message the message - * @param command the command - */ - public InvalidUsageException(@Nullable String message, CommandCallable command) { - this(message, command, false); - } - - /** - * Create a new instance with a message. - * - * @param message the message - * @param command the command - * @param fullHelpSuggested true if the full help for the command should be shown - */ - public InvalidUsageException(@Nullable String message, CommandCallable command, boolean fullHelpSuggested) { - super(message); - checkNotNull(command); - this.command = command; - this.fullHelpSuggested = fullHelpSuggested; - } - - /** - * Get the command. - * - * @return the command - */ - public CommandCallable getCommand() { - return command; - } - - /** - * Get a simple usage string. - * - * @param prefix the command shebang (such as "/") -- may be blank - * @return a usage string - */ - public String getSimpleUsageString(String prefix) { - return getCommandUsed(prefix, command.getDescription().getUsage()); - } - - /** - * Return whether the full usage of the command should be shown. - * - * @return show full usage - */ - public boolean isFullHelpSuggested() { - return fullHelpSuggested; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/MissingParameterException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/MissingParameterException.java deleted file mode 100644 index bbdf0e0d5..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/MissingParameterException.java +++ /dev/null @@ -1,29 +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 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.util.command; - -import com.sk89q.worldedit.util.command.parametric.ParameterException; - -/** - * Thrown when there is a missing parameter. - */ -public class MissingParameterException extends ParameterException { - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/NullCompleter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/NullCompleter.java deleted file mode 100644 index 10850c696..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/NullCompleter.java +++ /dev/null @@ -1,38 +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 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.util.command; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; - -import java.util.Collections; -import java.util.List; - -/** - * Always returns an empty list of suggestions. - */ -public class NullCompleter implements CommandCompleter { - - @Override - public List getSuggestions(String arguments, CommandLocals locals) throws CommandException { - return Collections.emptyList(); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Parameter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Parameter.java deleted file mode 100644 index a2ac4e343..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/Parameter.java +++ /dev/null @@ -1,66 +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 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.util.command; - -/** - * Describes a parameter. - * - * @see Description - */ -public interface Parameter { - - /** - * The name of the parameter. - * - * @return the name - */ - String getName(); - - /** - * Get the flag associated with this parameter. - * - * @return the flag, or null if there is no flag associated - * @see #isValueFlag() - */ - Character getFlag(); - - /** - * Return whether the flag is a value flag. - * - * @return true if the flag is a value flag - * @see #getFlag() - */ - boolean isValueFlag(); - - /** - * Get whether this parameter is optional. - * - * @return true if the parameter does not have to be specified - */ - boolean isOptional(); - - /** - * Get the default value as a string to be parsed by the binding. - * - * @return a default value, or null if none is set - */ - String[] getDefaultValue(); - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/PrimaryAliasComparator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/PrimaryAliasComparator.java deleted file mode 100644 index bca779d4b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/PrimaryAliasComparator.java +++ /dev/null @@ -1,60 +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 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.util.command; - -import java.util.Comparator; -import java.util.regex.Pattern; - -import javax.annotation.Nullable; - -/** - * Compares the primary aliases of two {@link CommandMapping} using - * {@link String#compareTo(String)}. - */ -public final class PrimaryAliasComparator implements Comparator { - - /** - * An instance of this class. - */ - public static final PrimaryAliasComparator INSTANCE = new PrimaryAliasComparator(null); - private final @Nullable Pattern removalPattern; - - /** - * Create a new instance. - * - * @param removalPattern a regex to remove unwanted characters from the compared aliases - */ - public PrimaryAliasComparator(@Nullable Pattern removalPattern) { - this.removalPattern = removalPattern; - } - - private String clean(String alias) { - if (removalPattern != null) { - return removalPattern.matcher(alias).replaceAll(""); - } - return alias; - } - - @Override - public int compare(CommandMapping o1, CommandMapping o2) { - return clean(o1.getPrimaryAlias()).compareTo(clean(o2.getPrimaryAlias())); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleCommandMapping.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleCommandMapping.java deleted file mode 100644 index 982832c48..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleCommandMapping.java +++ /dev/null @@ -1,72 +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 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.util.command; - -import java.util.Arrays; - -/** - * Tracks a command registration. - */ -public class SimpleCommandMapping implements CommandMapping { - - private final String[] aliases; - private final CommandCallable callable; - - /** - * Create a new instance. - * - * @param callable the command callable - * @param alias a list of all aliases, where the first one is the primary one - */ - public SimpleCommandMapping(CommandCallable callable, String... alias) { - super(); - this.aliases = alias; - this.callable = callable; - } - - @Override - public String getPrimaryAlias() { - return aliases[0]; - } - - @Override - public String[] getAllAliases() { - return aliases; - } - - @Override - public CommandCallable getCallable() { - return callable; - } - - @Override - public Description getDescription() { - return getCallable().getDescription(); - } - - @Override - public String toString() { - return "CommandMapping{" + - "aliases=" + Arrays.toString(aliases) + - ", callable=" + callable + - '}'; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java deleted file mode 100644 index 4bea65d91..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java +++ /dev/null @@ -1,135 +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 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.util.command; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A simple implementation of {@link Description} which has setters. - */ -public class SimpleDescription implements Description { - - private List parameters = new ArrayList<>(); - private List permissions = new ArrayList<>(); - private String description; - private String help; - private String overrideUsage; - - @Override - public List getParameters() { - return parameters; - } - - /** - * Set the list of parameters. - * - * @param parameters the list of parameters - * @see #getParameters() - */ - public SimpleDescription setParameters(List parameters) { - this.parameters = Collections.unmodifiableList(parameters); - return this; - } - - @Override - public String getDescription() { - return description; - } - - /** - * Set the description of the command. - * - * @param description the description - * @see #getDescription() - */ - public SimpleDescription setDescription(String description) { - this.description = description; - return this; - } - - @Override - public String getHelp() { - return help; - } - - /** - * Set the help text of the command. - * - * @param help the help text - * @see #getHelp() - */ - public SimpleDescription setHelp(String help) { - this.help = help; - return this; - } - - @Override - public List getPermissions() { - return permissions; - } - - /** - * Set the permissions of this command. - * - * @param permissions the permissions - */ - public SimpleDescription setPermissions(List permissions) { - this.permissions = Collections.unmodifiableList(permissions); - return this; - } - - /** - * Override the usage string returned with a given one. - * - * @param usage usage string, or null - */ - public SimpleDescription overrideUsage(String usage) { - this.overrideUsage = usage; - return this; - } - - @Override - public String getUsage() { - if (overrideUsage != null) { - return overrideUsage; - } - - StringBuilder builder = new StringBuilder(); - boolean first = true; - - for (Parameter parameter : parameters) { - if (!first) { - builder.append(" "); - } - builder.append(parameter); - first = false; - } - - return builder.toString(); - } - - @Override - public String toString() { - return getUsage(); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java deleted file mode 100644 index 8bb73a880..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java +++ /dev/null @@ -1,189 +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 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.util.command; - -import com.google.common.base.Joiner; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.minecraft.util.commands.CommandPermissionsException; -import com.sk89q.minecraft.util.commands.WrappedCommandException; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * A simple implementation of {@link Dispatcher}. - */ -public class SimpleDispatcher implements Dispatcher { - - private final Map commands = new HashMap<>(); - private final SimpleDescription description = new SimpleDescription(); - - /** - * Create a new instance. - */ - public SimpleDispatcher() { - description.getParameters().add(new SimpleParameter("subcommand")); - SimpleParameter extraArgs = new SimpleParameter("..."); - extraArgs.setOptional(true); - description.getParameters().add(extraArgs); - } - - @Override - public void registerCommand(CommandCallable callable, String... alias) { - CommandMapping mapping = new SimpleCommandMapping(callable, alias); - - // Check for replacements - for (String a : alias) { - String lower = a.toLowerCase(); - if (commands.containsKey(lower)) { - throw new IllegalArgumentException( - "Replacing commands is currently undefined behavior"); - } - } - - for (String a : alias) { - String lower = a.toLowerCase(); - commands.put(lower, mapping); - } - } - - @Override - public Set getCommands() { - return Collections.unmodifiableSet(new HashSet<>(commands.values())); - } - - @Override - public Set getAliases() { - return Collections.unmodifiableSet(commands.keySet()); - } - - @Override - public Set getPrimaryAliases() { - Set aliases = new HashSet<>(); - for (CommandMapping mapping : getCommands()) { - aliases.add(mapping.getPrimaryAlias()); - } - return Collections.unmodifiableSet(aliases); - } - - @Override - public boolean contains(String alias) { - return commands.containsKey(alias.toLowerCase()); - } - - @Override - public CommandMapping get(String alias) { - return commands.get(alias.toLowerCase()); - } - - @Override - public Object call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException { - // We have permission for this command if we have permissions for subcommands - if (parentCommands.length != 0 && !testPermission(locals)) { - throw new CommandPermissionsException(); - } - - String[] split = CommandContext.split(arguments); - Set aliases = getPrimaryAliases(); - - if (aliases.isEmpty()) { - throw new InvalidUsageException("This command has no sub-commands.", this); - } else if (split.length > 0) { - String subCommand = split[0]; - String subArguments = Joiner.on(" ").join(Arrays.copyOfRange(split, 1, split.length)); - String[] subParents = Arrays.copyOf(parentCommands, parentCommands.length + 1); - subParents[parentCommands.length] = subCommand; - CommandMapping mapping = get(subCommand); - - if (mapping != null) { - try { - return mapping.getCallable().call(subArguments, locals, subParents); - } catch (CommandException e) { - e.prependStack(subCommand); - throw e; - } catch (Throwable t) { - throw new WrappedCommandException(t); - } - } - - } - - throw new InvalidUsageException("Please choose a sub-command.", this, true); - } - - @Override - public List getSuggestions(String arguments, CommandLocals locals) throws CommandException { - String[] split = CommandContext.split(arguments); - - if (split.length <= 1) { - String prefix = split.length > 0 ? split[0] : ""; - - List suggestions = new ArrayList<>(); - - for (CommandMapping mapping : getCommands()) { - if (mapping.getCallable().testPermission(locals)) { - for (String alias : mapping.getAllAliases()) { - if (prefix.isEmpty() || alias.startsWith(arguments)) { - suggestions.add(mapping.getPrimaryAlias()); - break; - } - } - } - } - - return suggestions; - } else { - String subCommand = split[0]; - CommandMapping mapping = get(subCommand); - String passedArguments = Joiner.on(" ").join(Arrays.copyOfRange(split, 1, split.length)); - - if (mapping != null) { - return mapping.getCallable().getSuggestions(passedArguments, locals); - } else { - return Collections.emptyList(); - } - } - } - - @Override - public SimpleDescription getDescription() { - return description; - } - - @Override - public boolean testPermission(CommandLocals locals) { - for (CommandMapping mapping : getCommands()) { - if (mapping.getCallable().testPermission(locals)) { - return true; - } - } - - return false; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleParameter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleParameter.java deleted file mode 100644 index ac9fcfdaa..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/SimpleParameter.java +++ /dev/null @@ -1,134 +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 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.util.command; - -/** - * A simple implementation of {@link Parameter} that has setters. - */ -public class SimpleParameter implements Parameter { - - private String name; - private Character flag; - private boolean isValue; - private boolean isOptional; - private String[] defaultValue; - - /** - * Create a new parameter with no name defined yet. - */ - public SimpleParameter() { - } - - /** - * Create a new parameter of the given name. - * - * @param name the name - */ - public SimpleParameter(String name) { - this.name = name; - } - - @Override - public String getName() { - return name; - } - - /** - * Set the name of the parameter. - * - * @param name the parameter name - */ - public SimpleParameter setName(String name) { - this.name = name; - return this; - } - - @Override - public Character getFlag() { - return flag; - } - - @Override - public boolean isValueFlag() { - return flag != null && isValue; - } - - /** - * Set the flag used by this parameter. - * @param flag the flag, or null if there is no flag - * @param isValue true if the flag is a value flag - */ - public SimpleParameter setFlag(Character flag, boolean isValue) { - this.flag = flag; - this.isValue = isValue; - return this; - } - - @Override - public boolean isOptional() { - return isOptional || getFlag() != null; - } - - /** - * Set whether this parameter is optional. - * - * @param isOptional true if this parameter is optional - */ - public SimpleParameter setOptional(boolean isOptional) { - this.isOptional = isOptional; - return this; - } - - @Override - public String[] getDefaultValue() { - return defaultValue; - } - - /** - * Set the default value. - * - * @param defaultValue a default value, or null if none - */ - public SimpleParameter setDefaultValue(String[] defaultValue) { - this.defaultValue = defaultValue; - return this; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (getFlag() != null) { - if (isValueFlag()) { - builder.append("[-") - .append(getFlag()).append(" <").append(getName()).append(">]"); - } else { - builder.append("[-").append(getFlag()).append("]"); - } - } else { - if (isOptional()) { - builder.append("[<").append(getName()).append(">]"); - } else { - builder.append("<").append(getName()).append(">"); - } - } - return builder.toString(); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/UnconsumedParameterException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/UnconsumedParameterException.java deleted file mode 100644 index 0a399f64d..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/UnconsumedParameterException.java +++ /dev/null @@ -1,40 +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 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.util.command; - -import com.sk89q.worldedit.util.command.parametric.ParameterException; - -/** - * Thrown when there are leftover parameters that were not consumed, particular in the - * case of the user providing too many parameters. - */ -public class UnconsumedParameterException extends ParameterException { - - private String unconsumed; - - public UnconsumedParameterException(String unconsumed) { - this.unconsumed = unconsumed; - } - - public String getUnconsumed() { - return unconsumed; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentException.java deleted file mode 100644 index 37dc70f86..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentException.java +++ /dev/null @@ -1,39 +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 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.util.command.argument; - -public class ArgumentException extends Exception { - - public ArgumentException() { - } - - public ArgumentException(String message) { - super(message); - } - - public ArgumentException(String message, Throwable cause) { - super(message, cause); - } - - public ArgumentException(Throwable cause) { - super(cause); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentParseException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentParseException.java deleted file mode 100644 index fd2fc6f4f..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentParseException.java +++ /dev/null @@ -1,39 +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 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.util.command.argument; - -public class ArgumentParseException extends ArgumentException { - - public ArgumentParseException() { - } - - public ArgumentParseException(String message) { - super(message); - } - - public ArgumentParseException(String message, Throwable cause) { - super(message, cause); - } - - public ArgumentParseException(Throwable cause) { - super(cause); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java deleted file mode 100644 index 22141fedd..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/ArgumentUtils.java +++ /dev/null @@ -1,45 +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 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.util.command.argument; - -import com.google.common.collect.Lists; - -import java.util.Collection; -import java.util.List; - -public final class ArgumentUtils { - - private ArgumentUtils() { - } - - public static List getMatchingSuggestions(Collection items, String s) { - if (s.isEmpty()) { - return Lists.newArrayList(items); - } - List suggestions = Lists.newArrayList(); - for (String item : items) { - if (item.toLowerCase().startsWith(s)) { - suggestions.add(item); - } - } - return suggestions; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/CommandArgs.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/CommandArgs.java deleted file mode 100644 index 7c91149e8..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/CommandArgs.java +++ /dev/null @@ -1,162 +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 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.util.command.argument; - -import com.google.common.collect.Lists; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; - -import java.util.Collections; -import java.util.List; - -public class CommandArgs { - - private final List arguments; - private int position = 0; - - public CommandArgs(List arguments) { - this.arguments = arguments; - } - - public CommandArgs(CommandArgs args) { - this(Lists.newArrayList(args.arguments)); - } - - public boolean hasNext() { - return position < arguments.size(); - } - - public String next() throws MissingArgumentException { - try { - return arguments.get(position++); - } catch (IndexOutOfBoundsException ignored) { - throw new MissingArgumentException("Too few arguments specified."); - } - } - - public String uncheckedNext() { - if (hasNext()) { - return arguments.get(position); - } else { - return null; - } - } - - public String peek() throws MissingArgumentException { - try { - return arguments.get(position); - } catch (IndexOutOfBoundsException ignored) { - throw new MissingArgumentException("Too few arguments specified."); - } - } - - public String uncheckedPeek() { - if (hasNext()) { - return arguments.get(position); - } else { - return null; - } - } - - public String remaining() throws MissingArgumentException { - if (hasNext()) { - StringBuilder builder = new StringBuilder(); - boolean first = true; - while (hasNext()) { - if (!first) { - builder.append(" "); - } - builder.append(next()); - first = false; - } - return builder.toString(); - } else { - throw new MissingArgumentException("Too few arguments specified."); - } - } - - public String peekRemaining() throws MissingArgumentException { - if (hasNext()) { - StringBuilder builder = new StringBuilder(); - boolean first = true; - while (hasNext()) { - if (!first) { - builder.append(" "); - } - builder.append(next()); - first = false; - } - return builder.toString(); - } else { - throw new MissingArgumentException(); - } - } - - public int position() { - return position; - } - - public int size() { - return arguments.size(); - } - - public void markConsumed() { - position = arguments.size(); - } - - public void requireAllConsumed() throws UnusedArgumentsException { - if (hasNext()) { - StringBuilder builder = new StringBuilder(); - try { - builder.append(peekRemaining()); - } catch (MissingArgumentException e) { - throw new RuntimeException("This should not have happened", e); - } - throw new UnusedArgumentsException("There were unused arguments: " + builder); - } - } - - public static class Parser { - private boolean usingHangingArguments = false; - - public boolean isUsingHangingArguments() { - return usingHangingArguments; - } - - public Parser setUsingHangingArguments(boolean usingHangingArguments) { - this.usingHangingArguments = usingHangingArguments; - return this; - } - - public CommandArgs parse(String arguments) throws CommandException { - CommandContext context = new CommandContext(CommandContext.split("_ " + arguments), Collections.emptySet(), false, null, false); - List args = Lists.newArrayList(); - for (int i = 0; i < context.argsLength(); i++) { - args.add(context.getString(i)); - } - if (isUsingHangingArguments()) { - if (arguments.isEmpty() || arguments.endsWith(" ")) { - args.add(""); - } - } - return new CommandArgs(args); - } - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/MissingArgumentException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/MissingArgumentException.java deleted file mode 100644 index db0267727..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/MissingArgumentException.java +++ /dev/null @@ -1,39 +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 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.util.command.argument; - -public class MissingArgumentException extends ArgumentException { - - public MissingArgumentException() { - } - - public MissingArgumentException(String message) { - super(message); - } - - public MissingArgumentException(String message, Throwable cause) { - super(message, cause); - } - - public MissingArgumentException(Throwable cause) { - super(cause); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/UnusedArgumentsException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/UnusedArgumentsException.java deleted file mode 100644 index efd7984e5..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/argument/UnusedArgumentsException.java +++ /dev/null @@ -1,39 +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 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.util.command.argument; - -public class UnusedArgumentsException extends ArgumentException { - - public UnusedArgumentsException() { - } - - public UnusedArgumentsException(String message) { - super(message); - } - - public UnusedArgumentsException(String message, Throwable cause) { - super(message, cause); - } - - public UnusedArgumentsException(Throwable cause) { - super(cause); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/PrimitiveBindings.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/PrimitiveBindings.java deleted file mode 100644 index 3a4d78edf..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/PrimitiveBindings.java +++ /dev/null @@ -1,294 +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 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.util.command.binding; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.ExpressionException; -import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; -import com.sk89q.worldedit.util.command.parametric.ArgumentStack; -import com.sk89q.worldedit.util.command.parametric.BindingBehavior; -import com.sk89q.worldedit.util.command.parametric.BindingHelper; -import com.sk89q.worldedit.util.command.parametric.BindingMatch; -import com.sk89q.worldedit.util.command.parametric.ParameterException; - -import java.lang.annotation.Annotation; - -import javax.annotation.Nullable; - -/** - * Handles basic Java types such as {@link String}s, {@link Byte}s, etc. - * - *

Handles both the object and primitive types.

- */ -public final class PrimitiveBindings extends BindingHelper { - - /** - * Gets a type from a {@link ArgumentStack}. - * - * @param context the context - * @param text the text annotation - * @param modifiers a list of modifiers - * @return the requested type - * @throws ParameterException on error - */ - @BindingMatch(classifier = Text.class, - type = String.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = -1, - provideModifiers = true) - public String getText(ArgumentStack context, Text text, Annotation[] modifiers) - throws ParameterException { - String v = context.remaining(); - validate(v, modifiers); - return v; - } - - /** - * Gets a type from a {@link ArgumentStack}. - * - * @param context the context - * @param modifiers a list of modifiers - * @return the requested type - * @throws ParameterException on error - */ - @BindingMatch(type = String.class, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) - public String getString(ArgumentStack context, Annotation[] modifiers) - throws ParameterException { - String v = context.next(); - validate(v, modifiers); - return v; - } - - /** - * Gets a type from a {@link ArgumentStack}. - * - * @param context the context - * @return the requested type - * @throws ParameterException on error - */ - @BindingMatch(type = { Boolean.class, boolean.class }, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1) - public Boolean getBoolean(ArgumentStack context) throws ParameterException { - return context.nextBoolean(); - } - - /** - * Try to parse numeric input as either a number or a mathematical expression. - * - * @param input input - * @return a number - * @throws ParameterException thrown on parse error - */ - private @Nullable Double parseNumericInput(@Nullable String input) throws ParameterException { - if (input == null) { - return null; - } - - try { - return Double.parseDouble(input); - } catch (NumberFormatException e1) { - try { - Expression expression = Expression.compile(input); - return expression.evaluate(); - } catch (EvaluationException e) { - throw new ParameterException(String.format( - "Expected '%s' to be a valid number (or a valid mathematical expression)", input)); - } catch (ExpressionException e) { - throw new ParameterException(String.format( - "Expected '%s' to be a number or valid math expression (error: %s)", input, e.getMessage())); - } - - } - } - - /** - * Gets a type from a {@link ArgumentStack}. - * - * @param context the context - * @param modifiers a list of modifiers - * @return the requested type - * @throws ParameterException on error - */ - @BindingMatch(type = { Integer.class, int.class }, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) - public Integer getInteger(ArgumentStack context, Annotation[] modifiers) throws ParameterException { - Double v = parseNumericInput(context.next()); - if (v != null) { - int intValue = v.intValue(); - validate(intValue, modifiers); - return intValue; - } else { - return null; - } - } - - /** - * Gets a type from a {@link ArgumentStack}. - * - * @param context the context - * @param modifiers a list of modifiers - * @return the requested type - * @throws ParameterException on error - */ - @BindingMatch(type = { Short.class, short.class }, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) - public Short getShort(ArgumentStack context, Annotation[] modifiers) throws ParameterException { - Integer v = getInteger(context, modifiers); - if (v != null) { - return v.shortValue(); - } - return null; - } - - /** - * Gets a type from a {@link ArgumentStack}. - * - * @param context the context - * @param modifiers a list of modifiers - * @return the requested type - * @throws ParameterException on error - */ - @BindingMatch(type = { Double.class, double.class }, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) - public Double getDouble(ArgumentStack context, Annotation[] modifiers) throws ParameterException { - Double v = parseNumericInput(context.next()); - if (v != null) { - validate(v, modifiers); - return v; - } else { - return null; - } - } - - /** - * Gets a type from a {@link ArgumentStack}. - * - * @param context the context - * @param modifiers a list of modifiers - * @return the requested type - * @throws ParameterException on error - */ - @BindingMatch(type = { Float.class, float.class }, - behavior = BindingBehavior.CONSUMES, - consumedCount = 1, - provideModifiers = true) - public Float getFloat(ArgumentStack context, Annotation[] modifiers) throws ParameterException { - Double v = getDouble(context, modifiers); - if (v != null) { - return v.floatValue(); - } - return null; - } - - /** - * Validate a number value using relevant modifiers. - * - * @param number the number - * @param modifiers the list of modifiers to scan - * @throws ParameterException on a validation error - */ - private static void validate(double number, Annotation[] modifiers) - throws ParameterException { - for (Annotation modifier : modifiers) { - if (modifier instanceof Range) { - Range range = (Range) modifier; - if (number < range.min()) { - throw new ParameterException( - String.format( - "A valid value is greater than or equal to %s " + - "(you entered %s)", range.min(), number)); - } else if (number > range.max()) { - throw new ParameterException( - String.format( - "A valid value is less than or equal to %s " + - "(you entered %s)", range.max(), number)); - } - } - } - } - - /** - * Validate a number value using relevant modifiers. - * - * @param number the number - * @param modifiers the list of modifiers to scan - * @throws ParameterException on a validation error - */ - private static void validate(int number, Annotation[] modifiers) - throws ParameterException { - for (Annotation modifier : modifiers) { - if (modifier instanceof Range) { - Range range = (Range) modifier; - if (number < range.min()) { - throw new ParameterException( - String.format( - "A valid value is greater than or equal to %s " + - "(you entered %s)", range.min(), number)); - } else if (number > range.max()) { - throw new ParameterException( - String.format( - "A valid value is less than or equal to %s " + - "(you entered %s)", range.max(), number)); - } - } - } - } - - /** - * Validate a string value using relevant modifiers. - * - * @param string the string - * @param modifiers the list of modifiers to scan - * @throws ParameterException on a validation error - */ - private static void validate(String string, Annotation[] modifiers) - throws ParameterException { - if (string == null) { - return; - } - - for (Annotation modifier : modifiers) { - if (modifier instanceof Validate) { - Validate validate = (Validate) modifier; - - if (!validate.regex().isEmpty()) { - if (!string.matches(validate.regex())) { - throw new ParameterException( - String.format( - "The given text doesn't match the right " + - "format (technically speaking, the 'format' is %s)", - validate.regex())); - } - } - } - } - } - -} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Range.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Range.java deleted file mode 100644 index 0ff21ca12..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Range.java +++ /dev/null @@ -1,50 +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 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.util.command.binding; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Specifies a range of values for numbers. - * - * @see PrimitiveBindings a user of this annotation as a modifier - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface Range { - - /** - * The minimum value that the number can be at, inclusive. - * - * @return the minimum value - */ - double min() default Double.MIN_VALUE; - - /** - * The maximum value that the number can be at, inclusive. - * - * @return the maximum value - */ - double max() default Double.MAX_VALUE; - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/StandardBindings.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/StandardBindings.java deleted file mode 100644 index a5a06e5fe..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/StandardBindings.java +++ /dev/null @@ -1,46 +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 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.util.command.binding; - -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.worldedit.util.command.parametric.ArgumentStack; -import com.sk89q.worldedit.util.command.parametric.BindingBehavior; -import com.sk89q.worldedit.util.command.parametric.BindingHelper; -import com.sk89q.worldedit.util.command.parametric.BindingMatch; - -/** - * Standard bindings that should be available to most configurations. - */ -public final class StandardBindings extends BindingHelper { - - /** - * Gets a {@link CommandContext} from a {@link ArgumentStack}. - * - * @param context the context - * @return a selection - */ - @BindingMatch(type = CommandContext.class, - behavior = BindingBehavior.PROVIDES) - public CommandContext getCommandContext(ArgumentStack context) { - context.markConsumed(); // Consume entire stack - return context.getContext(); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Switch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Switch.java deleted file mode 100644 index 8d0e122ff..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Switch.java +++ /dev/null @@ -1,44 +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 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.util.command.binding; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates a command flag, such as {@code /command -f}. - * - *

If used on a boolean type, then the flag will be a non-value flag. If - * used on any other type, then the flag will be a value flag.

- */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface Switch { - - /** - * The flag character. - * - * @return the flag character (A-Z a-z 0-9 is acceptable) - */ - char value(); - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Text.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Text.java deleted file mode 100644 index 030bc9ad4..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Text.java +++ /dev/null @@ -1,41 +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 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.util.command.binding; - -import com.sk89q.worldedit.util.command.parametric.ArgumentStack; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates a {@link String} parameter will call {@link ArgumentStack#remaining()} and - * therefore consume all remaining arguments. - * - *

This should only be used at the end of a list of parameters (of parameters that - * need to consume from the stack of arguments), otherwise following parameters will - * have no values left to consume.

- */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface Text { - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Validate.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Validate.java deleted file mode 100644 index 3686aa359..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/binding/Validate.java +++ /dev/null @@ -1,45 +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 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.util.command.binding; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.regex.Pattern; - -/** - * Used to validate a string. - * - * @see PrimitiveBindings where this validation is used - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface Validate { - - /** - * An optional regular expression that must match the string. - * - * @see Pattern regular expression class - * @return the pattern - */ - String regex() default ""; - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java deleted file mode 100644 index ce4ba58fe..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/BranchingCommand.java +++ /dev/null @@ -1,111 +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 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.util.command.composition; - -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.argument.ArgumentUtils; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.argument.MissingArgumentException; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -public abstract class BranchingCommand implements CommandExecutor { - - private final String name; - private final Map> options = Maps.newHashMap(); - private final Set primaryAliases = Sets.newHashSet(); - - public BranchingCommand(String name) { - this.name = name; - } - - public void putOption(CommandExecutor executor, String primaryAlias, String... aliases) { - options.put(primaryAlias, executor); - primaryAliases.add(primaryAlias); - for (String alias : aliases) { - options.put(alias, executor); - } - } - - @Override - public T call(CommandArgs args, CommandLocals locals) throws CommandException { - try { - String classifier = args.next(); - CommandExecutor executor = options.get(classifier.toLowerCase()); - if (executor != null) { - return executor.call(args, locals); - } else { - throw new CommandException("'" + classifier + "' isn't a valid option for '" + name + "'. " + - "Try one of: " + Joiner.on(", ").join(primaryAliases)); - } - } catch (MissingArgumentException e) { - throw new CommandException("Missing value for <" + name + "> " + - "(try one of " + Joiner.on(" | ").join(primaryAliases) + ")."); - } - } - - @Override - public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { - String classifier = args.next(); - try { - CommandExecutor executor = options.get(classifier.toLowerCase()); - if (executor != null) { - return executor.getSuggestions(args, locals); - } - } catch (MissingArgumentException ignored) { - } - - return ArgumentUtils.getMatchingSuggestions((classifier.isEmpty() ? primaryAliases : options.keySet()), classifier); - } - - @Override - public String getUsage() { - List optionUsages = Lists.newArrayList(); - for (String alias : primaryAliases) { - CommandExecutor executor = options.get(alias); - String usage = executor.getUsage(); - if (usage.isEmpty()) { - optionUsages.add(alias); - } else { - optionUsages.add(alias + " " + executor.getUsage()); - } - } - - return "(" + Joiner.on(" | ").join(optionUsages) + ")"; - } - - @Override - public boolean testPermission(CommandLocals locals) { - for (CommandExecutor executor : options.values()) { - if (!executor.testPermission(locals)) { - return false; - } - } - return true; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/CommandExecutor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/CommandExecutor.java deleted file mode 100644 index a9729884b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/CommandExecutor.java +++ /dev/null @@ -1,41 +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 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.util.command.composition; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.argument.MissingArgumentException; - -import java.util.List; - -public interface CommandExecutor { - - T call(CommandArgs args, CommandLocals locals) throws CommandException; - - List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException; - - String getUsage(); - - String getDescription(); - - boolean testPermission(CommandLocals locals); - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/FlagParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/FlagParser.java deleted file mode 100644 index fd64dd82d..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/FlagParser.java +++ /dev/null @@ -1,196 +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 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.util.command.composition; - -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.argument.MissingArgumentException; -import com.sk89q.worldedit.util.command.composition.FlagParser.FlagData; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import javax.annotation.Nullable; - -public class FlagParser implements CommandExecutor { - - private final Map> flags = Maps.newHashMap(); - - public Flag registerFlag(char flag, CommandExecutor executor) { - Flag ret = new Flag<>(flag); - flags.put(flag, executor); - return ret; - } - - @Override - public FlagData call(CommandArgs args, CommandLocals locals) throws CommandException { - Map values = Maps.newHashMap(); - try { - while (true) { - String next = args.peek(); - if (next.equals("--")) { - args.next(); - break; - } else if (next.length() > 0 && next.charAt(0) == '-') { - args.next(); - - if (next.length() == 1) { - throw new CommandException("- must be followed by a flag (like -a), otherwise use -- before the - (i.e. /cmd -- - is a dash)."); - } else { - for (int i = 1; i < next.length(); i++) { - char flag = next.charAt(i); - CommandExecutor executor = flags.get(flag); - if (executor != null) { - values.put(flag, executor.call(args, locals)); - } else { - throw new CommandException("Unknown flag: -" + flag + " (try one of -" + Joiner.on("").join(flags.keySet()) + " or put -- to skip flag parsing, i.e. /cmd -- -this begins with a dash)."); - } - } - } - } else { - break; - } - } - } catch (MissingArgumentException ignored) { - } - - return new FlagData(values); - } - - @Override - public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { - List suggestions = Collections.emptyList(); - - while (true) { - String next = args.peek(); - if (next.equals("--")) { - args.next(); - break; - } else if (next.length() > 0 && next.charAt(0) == '-') { - args.next(); - - if (!args.hasNext()) { // Completing -| or -???| - List flagSuggestions = Lists.newArrayList(); - for (Character flag : flags.keySet()) { - if (next.indexOf(flag) < 1) { // Don't add any flags that the user has entered - flagSuggestions.add(next + flag); - } - } - return flagSuggestions; - } else { // Completing -??? ???| - for (int i = 1; i < next.length(); i++) { - char flag = next.charAt(i); - CommandExecutor executor = flags.get(flag); - if (executor != null) { - suggestions = executor.getSuggestions(args, locals); - } else { - return suggestions; - } - } - } - } else { - return suggestions; - } - } - - return suggestions; - } - - @Override - public String getUsage() { - List options = Lists.newArrayList(); - for (Entry> entry : flags.entrySet()) { - String usage = entry.getValue().getUsage(); - options.add("[-" + entry.getKey() + (!usage.isEmpty() ? " " + usage : "") + "]"); - } - return Joiner.on(" ").join(options); - } - - @Override - public String getDescription() { - return "Read flags"; - } - - @Override - public boolean testPermission(CommandLocals locals) { - for (CommandExecutor executor : flags.values()) { - if (!executor.testPermission(locals)) { - return false; - } - } - - return true; - } - - public static class FlagData { - private final Map data; - - private FlagData(Map data) { - this.data = data; - } - - public int size() { - return data.size(); - } - - public boolean isEmpty() { - return data.isEmpty(); - } - - public Object get(char key) { - return data.get(key); - } - - public boolean containsKey(char key) { - return data.containsKey(key); - } - - } - - public static final class Flag { - private final char flag; - - private Flag(char flag) { - this.flag = flag; - } - - @SuppressWarnings("unchecked") - @Nullable - public T get(FlagData data) { - return (T) data.get(flag); - } - - public T get(FlagData data, T fallback) { - T value = get(data); - if (value == null) { - return fallback; - } else { - return value; - } - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/LegacyCommandAdapter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/LegacyCommandAdapter.java deleted file mode 100644 index f3470b67b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/LegacyCommandAdapter.java +++ /dev/null @@ -1,87 +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 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.util.command.composition; - -import com.google.common.collect.Lists; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.CommandCallable; -import com.sk89q.worldedit.util.command.Description; -import com.sk89q.worldedit.util.command.SimpleDescription; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.argument.MissingArgumentException; -import com.sk89q.worldedit.util.command.argument.UnusedArgumentsException; - -import java.util.List; - -public class LegacyCommandAdapter implements CommandCallable { - - private final CommandExecutor executor; - - private LegacyCommandAdapter(CommandExecutor executor) { - this.executor = executor; - } - - @Override - public final Object call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException { - CommandArgs args = new CommandArgs.Parser().parse(arguments); - - if (args.hasNext()) { - if (args.uncheckedPeek().equals("-?")) { - throw new CommandException(executor.getUsage()); - } - } - - Object ret = executor.call(args, locals); - try { - args.requireAllConsumed(); - } catch (UnusedArgumentsException e) { - throw new CommandException(e.getMessage()); - } - return ret; - } - - @Override - public Description getDescription() { - return new SimpleDescription() - .setDescription(executor.getDescription()) - .overrideUsage(executor.getUsage()); - } - - @Override - public boolean testPermission(CommandLocals locals) { - return executor.testPermission(locals); - } - - @Override - public List getSuggestions(String arguments, CommandLocals locals) throws CommandException { - CommandArgs args = new CommandArgs.Parser().setUsingHangingArguments(true).parse(arguments); - try { - return executor.getSuggestions(args, locals); - } catch (MissingArgumentException e) { - return Lists.newArrayList(); - } - } - - public static LegacyCommandAdapter adapt(CommandExecutor executor) { - return new LegacyCommandAdapter(executor); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ParameterCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ParameterCommand.java deleted file mode 100644 index 8580f4f6d..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ParameterCommand.java +++ /dev/null @@ -1,79 +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 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.util.command.composition; - -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.composition.FlagParser.Flag; - -import java.util.List; - -public abstract class ParameterCommand implements CommandExecutor { - - private final List> parameters = Lists.newArrayList(); - private final FlagParser flagParser = new FlagParser(); - - public ParameterCommand() { - addParameter(flagParser); - } - - protected List> getParameters() { - return parameters; - } - - public > E addParameter(E executor) { - parameters.add(executor); - return executor; - } - - public Flag addFlag(char flag, CommandExecutor executor) { - return flagParser.registerFlag(flag, executor); - } - - protected FlagParser getFlagParser() { - return flagParser; - } - - @Override - public final String getUsage() { - List parts = Lists.newArrayList(); - for (CommandExecutor executor : parameters) { - String usage = executor.getUsage(); - if (!usage.isEmpty()) { - parts.add(executor.getUsage()); - } - } - return Joiner.on(" ").join(parts); - } - - @Override - public final boolean testPermission(CommandLocals locals) { - for (CommandExecutor executor : parameters) { - if (!executor.testPermission(locals)) { - return false; - } - } - return testPermission0(locals); - } - - protected abstract boolean testPermission0(CommandLocals locals); - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ProvidedValue.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ProvidedValue.java deleted file mode 100644 index 5528728b7..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/ProvidedValue.java +++ /dev/null @@ -1,69 +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 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.util.command.composition; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.argument.MissingArgumentException; - -import java.util.Collections; -import java.util.List; - -public class ProvidedValue implements CommandExecutor { - - private final T value; - private final String description; - - private ProvidedValue(T value, String description) { - this.value = value; - this.description = description; - } - - @Override - public T call(CommandArgs args, CommandLocals locals) throws CommandException { - return value; - } - - @Override - public List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { - return Collections.emptyList(); - } - - @Override - public String getUsage() { - return ""; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public boolean testPermission(CommandLocals locals) { - return true; - } - - public static ProvidedValue create(T value, String description) { - return new ProvidedValue<>(value, description); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/SimpleCommand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/SimpleCommand.java deleted file mode 100644 index fbcf9602b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/composition/SimpleCommand.java +++ /dev/null @@ -1,54 +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 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.util.command.composition; - -import com.google.common.collect.Lists; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.argument.CommandArgs; -import com.sk89q.worldedit.util.command.argument.MissingArgumentException; - -import java.util.List; - -public abstract class SimpleCommand extends ParameterCommand { - - @Override - public final List getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException { - List suggestions = Lists.newArrayList(); - boolean seenParameter = false; - for (CommandExecutor parameter : getParameters()) { - try { - suggestions = parameter.getSuggestions(args, locals); - seenParameter = true; - } catch (MissingArgumentException e) { - if (seenParameter) { - return suggestions; - } else { - throw e; - } - } - - // There's nothing more anyway - if (args.position() == args.size()) { - return suggestions; - } - } - return suggestions; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/fluent/CommandGraph.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/fluent/CommandGraph.java deleted file mode 100644 index 1b9dacb32..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/fluent/CommandGraph.java +++ /dev/null @@ -1,84 +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 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.util.command.fluent; - -import com.sk89q.worldedit.util.command.Dispatcher; -import com.sk89q.worldedit.util.command.SimpleDispatcher; -import com.sk89q.worldedit.util.command.parametric.ParametricBuilder; - -/** - * A fluent interface to creating a command graph. - * - *

A command graph may have multiple commands, and multiple sub-commands below that, - * and possibly below that.

- */ -public class CommandGraph { - - private final DispatcherNode rootDispatcher; - private ParametricBuilder builder; - - /** - * Create a new command graph. - */ - public CommandGraph() { - SimpleDispatcher dispatcher = new SimpleDispatcher(); - rootDispatcher = new DispatcherNode(this, null, dispatcher); - } - - /** - * Get the root dispatcher node. - * - * @return the root dispatcher node - */ - public DispatcherNode commands() { - return rootDispatcher; - } - - /** - * Get the {@link ParametricBuilder}. - * - * @return the builder, or null. - */ - public ParametricBuilder getBuilder() { - return builder; - } - - /** - * Set the {@link ParametricBuilder} used for calls to - * {@link DispatcherNode#registerMethods(Object)}. - * - * @param builder the builder, or null - * @return this object - */ - public CommandGraph builder(ParametricBuilder builder) { - this.builder = builder; - return this; - } - - /** - * Get the root dispatcher. - * - * @return the root dispatcher - */ - public Dispatcher getDispatcher() { - return rootDispatcher.getDispatcher(); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java deleted file mode 100644 index 8bcbbfe85..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/fluent/DispatcherNode.java +++ /dev/null @@ -1,139 +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 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.util.command.fluent; - -import com.sk89q.worldedit.util.command.CommandCallable; -import com.sk89q.worldedit.util.command.Dispatcher; -import com.sk89q.worldedit.util.command.SimpleDispatcher; -import com.sk89q.worldedit.util.command.parametric.ParametricBuilder; - -/** - * A collection of commands. - */ -public class DispatcherNode { - - private final CommandGraph graph; - private final DispatcherNode parent; - private final SimpleDispatcher dispatcher; - - /** - * Create a new instance. - * - * @param graph the root fluent graph object - * @param parent the parent node, or null - * @param dispatcher the dispatcher for this node - */ - DispatcherNode(CommandGraph graph, DispatcherNode parent, - SimpleDispatcher dispatcher) { - this.graph = graph; - this.parent = parent; - this.dispatcher = dispatcher; - } - - /** - * Set the description. - * - *

This can only be used on {@link DispatcherNode}s returned by - * {@link #group(String...)}.

- * - * @param description the description - * @return this object - */ - public DispatcherNode describeAs(String description) { - dispatcher.getDescription().setDescription(description); - return this; - } - - /** - * Register a command with this dispatcher. - * - * @param callable the executor - * @param alias the list of aliases, where the first alias is the primary one - */ - public DispatcherNode register(CommandCallable callable, String... alias) { - dispatcher.registerCommand(callable, alias); - return this; - } - - /** - * Build and register a command with this dispatcher using the - * {@link ParametricBuilder} assigned on the root {@link CommandGraph}. - * - * @param object the object provided to the {@link ParametricBuilder} - * @return this object - * @see ParametricBuilder#registerMethodsAsCommands(com.sk89q.worldedit.util.command.Dispatcher, Object) - */ - public DispatcherNode registerMethods(Object object) { - ParametricBuilder builder = graph.getBuilder(); - if (builder == null) { - throw new RuntimeException("No ParametricBuilder set"); - } - builder.registerMethodsAsCommands(getDispatcher(), object); - return this; - } - - /** - * Create a new command that will contain sub-commands. - * - *

The object returned by this method can be used to add sub-commands. To - * return to this "parent" context, use {@link DispatcherNode#graph()}.

- * - * @param alias the list of aliases, where the first alias is the primary one - * @return an object to place sub-commands - */ - public DispatcherNode group(String... alias) { - SimpleDispatcher command = new SimpleDispatcher(); - getDispatcher().registerCommand(command, alias); - return new DispatcherNode(graph, this, command); - } - - /** - * Return the parent node. - * - * @return the parent node - * @throws RuntimeException if there is no parent node. - */ - public DispatcherNode parent() { - if (parent != null) { - return parent; - } - - throw new RuntimeException("This node does not have a parent"); - } - - /** - * Get the root command graph. - * - * @return the root command graph - */ - public CommandGraph graph() { - return graph; - } - - /** - * Get the underlying dispatcher of this object. - * - * @return the dispatcher - */ - public Dispatcher getDispatcher() { - return dispatcher; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/AbstractInvokeListener.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/AbstractInvokeListener.java deleted file mode 100644 index 65fadc101..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/AbstractInvokeListener.java +++ /dev/null @@ -1,36 +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 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.util.command.parametric; - -import com.sk89q.worldedit.util.command.SimpleDescription; - -import java.lang.reflect.Method; - -/** - * An abstract listener. - */ -public abstract class AbstractInvokeListener implements InvokeListener { - - @Override - public void updateDescription(Object object, Method method, - ParameterData[] parameters, SimpleDescription description) { - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ArgumentStack.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ArgumentStack.java deleted file mode 100644 index 0f0b9a52b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ArgumentStack.java +++ /dev/null @@ -1,78 +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 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.util.command.parametric; - -import com.sk89q.minecraft.util.commands.CommandContext; - -public interface ArgumentStack { - - /** - * Get the next string, which may come from the stack or a value flag. - * - * @return the value - * @throws ParameterException on a parameter error - */ - String next() throws ParameterException; - - /** - * Get the next integer, which may come from the stack or a value flag. - * - * @return the value - * @throws ParameterException on a parameter error - */ - Integer nextInt() throws ParameterException; - - /** - * Get the next double, which may come from the stack or a value flag. - * - * @return the value - * @throws ParameterException on a parameter error - */ - Double nextDouble() throws ParameterException; - - /** - * Get the next boolean, which may come from the stack or a value flag. - * - * @return the value - * @throws ParameterException on a parameter error - */ - Boolean nextBoolean() throws ParameterException; - - /** - * Get all remaining string values, which will consume the rest of the stack. - * - * @return the value - * @throws ParameterException on a parameter error - */ - String remaining() throws ParameterException; - - /** - * Set as completely consumed. - */ - void markConsumed(); - - /** - * Get the underlying context. - * - * @return the context - */ - CommandContext getContext(); - -} \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/Binding.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/Binding.java deleted file mode 100644 index 108fc1bf8..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/Binding.java +++ /dev/null @@ -1,93 +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 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.util.command.parametric; - -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.worldedit.util.command.binding.PrimitiveBindings; -import com.sk89q.worldedit.util.command.binding.StandardBindings; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Type; -import java.util.List; - -/** - * Used to parse user input for a command, based on available method types - * and annotations. - * - *

A binding can be used to handle several types at once. For a binding to be - * called, it must be registered with a {@link ParametricBuilder} with - * {@link ParametricBuilder#addBinding(Binding, java.lang.reflect.Type...)}.

- * - * @see PrimitiveBindings an example of primitive bindings - * @see StandardBindings standard bindings - */ -public interface Binding { - - /** - * Get the types that this binding handles. - * - * @return the types - */ - Type[] getTypes(); - - /** - * Get how this binding consumes from a {@link ArgumentStack}. - * - * @param parameter information about the parameter - * @return the behavior - */ - BindingBehavior getBehavior(ParameterData parameter); - - /** - * Get the number of arguments that this binding will consume, if this - * information is available. - * - *

This method must return -1 for binding behavior types that are not - * {@link BindingBehavior#CONSUMES}.

- * - * @param parameter information about the parameter - * @return the number of consumed arguments, or -1 if unknown or irrelevant - */ - int getConsumedCount(ParameterData parameter); - - /** - * Attempt to consume values (if required) from the given {@link ArgumentStack} - * in order to instantiate an object for the given parameter. - * - * @param parameter information about the parameter - * @param scoped the arguments the user has input - * @param onlyConsume true to only consume arguments - * @return an object parsed for the given parameter - * @throws ParameterException thrown if the parameter could not be formulated - * @throws CommandException on a command exception - */ - Object bind(ParameterData parameter, ArgumentStack scoped, boolean onlyConsume) - throws ParameterException, CommandException, InvocationTargetException; - - /** - * Get a list of suggestions for the given parameter and user arguments. - * - * @param parameter information about the parameter - * @param prefix what the user has typed so far (may be an empty string) - * @return a list of suggestions - */ - List getSuggestions(ParameterData parameter, String prefix); - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingBehavior.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingBehavior.java deleted file mode 100644 index eeef23dbd..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingBehavior.java +++ /dev/null @@ -1,52 +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 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.util.command.parametric; - -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.worldedit.util.command.binding.Switch; - -/** - * Determines the type of binding. - */ -public enum BindingBehavior { - - /** - * Always consumes from a {@link ArgumentStack}. - */ - CONSUMES, - - /** - * Sometimes consumes from a {@link ArgumentStack}. - * - *

Bindings that exhibit this behavior must be defined as a {@link Switch} - * by commands utilizing the given binding.

- */ - INDETERMINATE, - - /** - * Never consumes from a {@link ArgumentStack}. - * - *

Bindings that exhibit this behavior generate objects from other sources, - * such as from a {@link CommandLocals}. These are "magic" bindings that inject - * variables.

- */ - PROVIDES - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingHelper.java deleted file mode 100644 index 73b59f087..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingHelper.java +++ /dev/null @@ -1,224 +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 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.util.command.parametric; - -import com.sk89q.minecraft.util.commands.CommandException; - -import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A binding helper that uses the {@link BindingMatch} annotation to make - * writing bindings extremely easy. - * - *

Methods must have the following and only the following parameters:

- * - *
    - *
  • A {@link ArgumentStack}
  • - *
  • A {@link Annotation} if there is a classifier set
  • - *
  • A {@link Annotation}[] - * if there {@link BindingMatch#provideModifiers()} is true
  • - *
- * - *

Methods may throw any exception. Exceptions may be converted using a - * {@link ExceptionConverter} registered with the {@link ParametricBuilder}.

- */ -public class BindingHelper implements Binding { - - private final List bindings; - private final Type[] types; - - /** - * Create a new instance. - */ - public BindingHelper() { - List bindings = new ArrayList<>(); - List types = new ArrayList<>(); - - for (Method method : this.getClass().getMethods()) { - BindingMatch info = method.getAnnotation(BindingMatch.class); - if (info != null) { - Class classifier = null; - - // Set classifier - if (!info.classifier().equals(Annotation.class)) { - classifier = info.classifier(); - types.add(classifier); - } - - for (Type t : info.type()) { - Type type = null; - - // Set type - if (!t.equals(Class.class)) { - type = t; - if (classifier == null) { - types.add(type); // Only if there is no classifier set! - } - } - - // Check to see if at least one is set - if (type == null && classifier == null) { - throw new RuntimeException( - "A @BindingMatch needs either a type or classifier set"); - } - - BoundMethod handler = new BoundMethod(info, type, classifier, method); - bindings.add(handler); - } - } - } - - Collections.sort(bindings); - - this.bindings = bindings; - - Type[] typesArray = new Type[types.size()]; - types.toArray(typesArray); - this.types = typesArray; - - } - - /** - * Match a {@link BindingMatch} according to the given parameter. - * - * @param parameter the parameter - * @return a binding - */ - private BoundMethod match(ParameterData parameter) { - for (BoundMethod binding : bindings) { - Annotation classifer = parameter.getClassifier(); - Type type = parameter.getType(); - - if (binding.classifier != null) { - if (classifer != null && classifer.annotationType().equals(binding.classifier)) { - if (binding.type == null || binding.type.equals(type)) { - return binding; - } - } - } else if (binding.type.equals(type)) { - return binding; - } - } - - throw new RuntimeException("Unknown type"); - } - - @Override - public Type[] getTypes() { - return types; - } - - @Override - public int getConsumedCount(ParameterData parameter) { - return match(parameter).annotation.consumedCount(); - } - - @Override - public BindingBehavior getBehavior(ParameterData parameter) { - return match(parameter).annotation.behavior(); - } - - @Override - public Object bind(ParameterData parameter, ArgumentStack scoped, - boolean onlyConsume) throws ParameterException, CommandException, InvocationTargetException { - BoundMethod binding = match(parameter); - List args = new ArrayList<>(); - args.add(scoped); - - if (binding.classifier != null) { - args.add(parameter.getClassifier()); - } - - if (binding.annotation.provideModifiers()) { - args.add(parameter.getModifiers()); - } - - if (onlyConsume && binding.annotation.behavior() == BindingBehavior.PROVIDES) { - return null; // Nothing to consume, nothing to do - } - - Object[] argsArray = new Object[args.size()]; - args.toArray(argsArray); - - try { - return binding.method.invoke(this, argsArray); - } catch (IllegalArgumentException e) { - throw new RuntimeException( - "Processing of classifier " + parameter.getClassifier() + - " and type " + parameter.getType() + " failed for method\n" + - binding.method + "\nbecause the parameters for that method are wrong", e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - if (e.getCause() instanceof ParameterException) { - throw (ParameterException) e.getCause(); - } else if (e.getCause() instanceof CommandException) { - throw (CommandException) e.getCause(); - } - throw e; - } - } - - @Override - public List getSuggestions(ParameterData parameter, String prefix) { - return new ArrayList<>(); - } - - private static class BoundMethod implements Comparable { - private final BindingMatch annotation; - private final Type type; - private final Class classifier; - private final Method method; - - BoundMethod(BindingMatch annotation, Type type, - Class classifier, Method method) { - this.annotation = annotation; - this.type = type; - this.classifier = classifier; - this.method = method; - } - - @Override - public int compareTo(BoundMethod o) { - if (classifier != null && o.classifier == null) { - return -1; - } else if (classifier == null && o.classifier != null) { - return 1; - } else if (classifier != null && o.classifier != null) { - if (type != null && o.type == null) { - return -1; - } else if (type == null && o.type != null) { - return 1; - } else { - return 0; - } - } else { - return 0; - } - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingMatch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingMatch.java deleted file mode 100644 index 049d3dc4d..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/BindingMatch.java +++ /dev/null @@ -1,71 +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 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.util.command.parametric; - -import java.lang.annotation.Annotation; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Denotes a match of a binding. - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface BindingMatch { - - /** - * The classifier. - * - * @return the classifier, or {@link Annotation} if not set - */ - Class classifier() default Annotation.class; - - /** - * The type. - * - * @return the type, or {@link Class} if not set - */ - Class[] type() default Class.class; - - /** - * The binding behavior. - * - * @return the behavior - */ - BindingBehavior behavior(); - - /** - * Get the number of arguments that this binding consumes. - * - * @return -1 if unknown or irrelevant - */ - int consumedCount() default -1; - - /** - * Set whether an array of modifier annotations is provided in the list of - * arguments. - * - * @return true to provide modifiers - */ - boolean provideModifiers() default false; - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ContextArgumentStack.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ContextArgumentStack.java deleted file mode 100644 index c7222b9e1..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ContextArgumentStack.java +++ /dev/null @@ -1,178 +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 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.util.command.parametric; - -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.worldedit.util.command.MissingParameterException; - -/** - * Makes an instance of a {@link CommandContext} into a stack of arguments - * that can be consumed. - * - * @see ParametricBuilder a user of this class - */ -public class ContextArgumentStack implements ArgumentStack { - - private final CommandContext context; - private int index = 0; - private int markedIndex = 0; - - /** - * Create a new instance using the given context. - * - * @param context the context - */ - public ContextArgumentStack(CommandContext context) { - this.context = context; - } - - @Override - public String next() throws ParameterException { - try { - return context.getString(index++); - } catch (IndexOutOfBoundsException e) { - throw new MissingParameterException(); - } - } - - @Override - public Integer nextInt() throws ParameterException { - try { - return Integer.parseInt(next()); - } catch (NumberFormatException e) { - throw new ParameterException( - "Expected a number, got '" + context.getString(index - 1) + "'"); - } - } - - @Override - public Double nextDouble() throws ParameterException { - try { - return Double.parseDouble(next()); - } catch (NumberFormatException e) { - throw new ParameterException( - "Expected a number, got '" + context.getString(index - 1) + "'"); - } - } - - @Override - public Boolean nextBoolean() throws ParameterException { - try { - return next().equalsIgnoreCase("true"); - } catch (IndexOutOfBoundsException e) { - throw new MissingParameterException(); - } - } - - @Override - public String remaining() throws ParameterException { - try { - String value = context.getJoinedStrings(index); - index = context.argsLength(); - return value; - } catch (IndexOutOfBoundsException e) { - throw new MissingParameterException(); - } - } - - /** - * Get the unconsumed arguments left over, without touching the stack. - * - * @return the unconsumed arguments - */ - public String getUnconsumed() { - if (index >= context.argsLength()) { - return null; - } - - return context.getJoinedStrings(index); - } - - @Override - public void markConsumed() { - index = context.argsLength(); - } - - /** - * Return the current position. - * - * @return the position - */ - public int position() { - return index; - } - - /** - * Mark the current position of the stack. - * - *

The marked position initially starts at 0.

- */ - public void mark() { - markedIndex = index; - } - - /** - * Reset to the previously {@link #mark()}ed position of the stack, and return - * the arguments that were consumed between this point and that previous point. - * - *

The marked position initially starts at 0.

- * - * @return the consumed arguments - */ - public String reset() { - String value = context.getString(markedIndex, index); - index = markedIndex; - return value; - } - - /** - * Return whether any arguments were consumed between the marked position - * and the current position. - * - *

The marked position initially starts at 0.

- * - * @return true if values were consumed. - */ - public boolean wasConsumed() { - return markedIndex != index; - } - - /** - * Return the arguments that were consumed between this point and that marked point. - * - *

The marked position initially starts at 0.

- * - * @return the consumed arguments - */ - public String getConsumed() { - return context.getString(markedIndex, index); - } - - /** - * Get the underlying context. - * - * @return the context - */ - @Override - public CommandContext getContext() { - return context; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java index 3ab0dda59..e943cd6e9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java @@ -24,27 +24,26 @@ import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.CommandExecutionException; /** - * Used to convert a recognized {@link Throwable} into an appropriate + * Used to convert a recognized {@link Throwable} into an appropriate * {@link CommandException}. - * - *

Methods (when invoked by a {@link ParametricBuilder}-created command) may throw - * relevant exceptions that are not caught by the command manager, but translate - * into reasonable exceptions for an application. However, unknown exceptions are + * + *

Methods may throw relevant exceptions that are not caught by the command manager, + * but translate into reasonable exceptions for an application. However, unknown exceptions are * normally simply wrapped in a {@link CommandExecutionException} and bubbled up. Only * normal {@link CommandException}s will be printed correctly, so a converter translates * one of these unknown exceptions into an appropriate {@link CommandException}.

- * + * *

This also allows the code calling the command to not need be aware of these * application-specific exceptions, as they will all be converted to * {@link CommandException}s that are handled normally.

*/ public interface ExceptionConverter { - + /** * Attempt to convert the given throwable into a {@link CommandException}. - * + * *

If the exception is not recognized, then nothing should be thrown.

- * + * * @param t the throwable * @throws CommandException a command exception */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/InvokeHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/InvokeHandler.java deleted file mode 100644 index 465f89689..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/InvokeHandler.java +++ /dev/null @@ -1,82 +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 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.util.command.parametric; - -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; - -import java.lang.reflect.Method; - -/** - * Called before and after a command is invoked for commands executed by a command - * created using {@link ParametricBuilder}. - * - *

Invocation handlers are created by {@link InvokeListener}s. Multiple - * listeners and handlers can be registered, and all be run. However, if one handler - * throws an exception, future handlers will not execute and the command will - * not execute (if thrown in - * {@link #preInvoke(Object, Method, ParameterData[], Object[], CommandContext)}).

- * - * @see InvokeListener the factory - */ -public interface InvokeHandler { - - /** - * Called before parameters are processed. - * - * @param object the object - * @param method the method - * @param parameters the list of parameters - * @param context the context - * @throws CommandException can be thrown for an error, which will stop invocation - * @throws ParameterException on parameter error - */ - void preProcess(Object object, Method method, ParameterData[] parameters, - CommandContext context) throws CommandException, ParameterException; - - /** - * Called before the parameter is invoked. - * - * @param object the object - * @param method the method - * @param parameters the list of parameters - * @param args the arguments to be given to the method - * @param context the context - * @throws CommandException can be thrown for an error, which will stop invocation - * @throws ParameterException on parameter error - */ - void preInvoke(Object object, Method method, ParameterData[] parameters, - Object[] args, CommandContext context) throws CommandException, ParameterException; - - /** - * Called after the parameter is invoked. - * - * @param object the object - * @param method the method - * @param parameters the list of parameters - * @param args the arguments to be given to the method - * @param context the context - * @throws CommandException can be thrown for an error - * @throws ParameterException on parameter error - */ - void postInvoke(Object object, Method method, ParameterData[] parameters, - Object[] args, CommandContext context) throws CommandException, ParameterException; - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/InvokeListener.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/InvokeListener.java deleted file mode 100644 index f30f86c9f..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/InvokeListener.java +++ /dev/null @@ -1,58 +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 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.util.command.parametric; - -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.worldedit.util.command.CommandCallable; -import com.sk89q.worldedit.util.command.SimpleDescription; - -import java.lang.reflect.Method; - -/** - * Listens to events related to {@link ParametricBuilder}. - */ -public interface InvokeListener { - - /** - * Create a new invocation handler. - * - *

An example use of an {@link InvokeHandler} would be to verify permissions - * added by the {@link CommandPermissions} annotation.

- * - *

For simple {@link InvokeHandler}, an object can implement both this - * interface and {@link InvokeHandler}.

- * - * @return a new invocation handler - */ - InvokeHandler createInvokeHandler(); - - /** - * During creation of a {@link CommandCallable} by a {@link ParametricBuilder}, - * this will be called in case the description needs to be updated. - * - * @param object the object - * @param method the method - * @param parameters a list of parameters - * @param description the description to be updated - */ - void updateDescription(Object object, Method method, ParameterData[] parameters, - SimpleDescription description); - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/LegacyCommandsHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/LegacyCommandsHandler.java deleted file mode 100644 index fbc1794c2..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/LegacyCommandsHandler.java +++ /dev/null @@ -1,97 +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 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.util.command.parametric; - -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.worldedit.util.command.MissingParameterException; -import com.sk89q.worldedit.util.command.SimpleDescription; -import com.sk89q.worldedit.util.command.UnconsumedParameterException; - -import java.lang.reflect.Method; - -/** - * Handles legacy properties on {@link Command} such as {@link Command#min()} and - * {@link Command#max()}. - */ -public class LegacyCommandsHandler extends AbstractInvokeListener implements InvokeHandler { - - @Override - public InvokeHandler createInvokeHandler() { - return this; - } - - @Override - public void preProcess(Object object, Method method, - ParameterData[] parameters, CommandContext context) - throws CommandException, ParameterException { - } - - @Override - public void preInvoke(Object object, Method method, - ParameterData[] parameters, Object[] args, CommandContext context) - throws ParameterException { - Command annotation = method.getAnnotation(Command.class); - - if (annotation != null) { - if (context.argsLength() < annotation.min()) { - throw new MissingParameterException(); - } - - if (annotation.max() != -1 && context.argsLength() > annotation.max()) { - throw new UnconsumedParameterException( - context.getRemainingString(annotation.max())); - } - } - } - - @Override - public void postInvoke(Object object, Method method, - ParameterData[] parameters, Object[] args, CommandContext context) { - - } - - @Override - public void updateDescription(Object object, Method method, - ParameterData[] parameters, SimpleDescription description) { - Command annotation = method.getAnnotation(Command.class); - - // Handle the case for old commands where no usage is set and all of its - // parameters are provider bindings, so its usage information would - // be blank and would imply that there were no accepted parameters - if (annotation != null && annotation.usage().isEmpty() - && (annotation.min() > 0 || annotation.max() > 0)) { - boolean hasUserParameters = false; - - for (ParameterData parameter : parameters) { - if (parameter.getBinding().getBehavior(parameter) != BindingBehavior.PROVIDES) { - hasUserParameters = true; - break; - } - } - - if (!hasUserParameters) { - description.overrideUsage("(unknown usage information)"); - } - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/Optional.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/Optional.java deleted file mode 100644 index bd6d5448f..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/Optional.java +++ /dev/null @@ -1,41 +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 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.util.command.parametric; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Indicates an optional parameter. - */ -@Target(ElementType.PARAMETER) -@Retention(RetentionPolicy.RUNTIME) -public @interface Optional { - - /** - * The default value to use if no value is set. - * - * @return a string value, or an empty list - */ - String[] value() default {}; - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterData.java deleted file mode 100644 index 649c576b4..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterData.java +++ /dev/null @@ -1,194 +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 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.util.command.parametric; - -import com.sk89q.worldedit.util.command.SimpleParameter; -import com.sk89q.worldedit.util.command.binding.PrimitiveBindings; -import com.sk89q.worldedit.util.command.binding.Range; -import com.sk89q.worldedit.util.command.binding.Text; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Type; - -/** - * Describes a parameter in detail. - */ -public class ParameterData extends SimpleParameter { - - private Binding binding; - private Annotation classifier; - private Annotation[] modifiers; - private Type type; - - /** - * Get the binding associated with this parameter. - * - * @return the binding - */ - public Binding getBinding() { - return binding; - } - - /** - * Set the binding associated with this parameter. - * - * @param binding the binding - */ - void setBinding(Binding binding) { - this.binding = binding; - } - - /** - * Set the main type of this parameter. - * - *

The type is normally that is used to determine which binding is used - * for a particular method's parameter.

- * - * @return the main type - * @see #getClassifier() which can override the type - */ - public Type getType() { - return type; - } - - /** - * Set the main type of this parameter. - * - * @param type the main type - */ - void setType(Type type) { - this.type = type; - } - - /** - * Get the classifier annotation. - * - *

Normally, the type determines what binding is called, but classifiers - * take precedence if one is found (and registered with - * {@link ParametricBuilder#addBinding(Binding, Type...)}). - * An example of a classifier annotation is {@link Text}.

- * - * @return the classifier annotation, null is possible - */ - public Annotation getClassifier() { - return classifier; - } - - /** - * Set the classifier annotation. - * - * @param classifier the classifier annotation, null is possible - */ - void setClassifier(Annotation classifier) { - this.classifier = classifier; - } - - /** - * Get a list of modifier annotations. - * - *

Modifier annotations are not considered in the process of choosing a binding - * for a method parameter, but they can be used to modify the behavior of a binding. - * An example of a modifier annotation is {@link Range}, which can restrict - * numeric values handled by {@link PrimitiveBindings} to be within a range. The list - * of annotations may contain a classifier and other unrelated annotations.

- * - * @return a list of annotations - */ - public Annotation[] getModifiers() { - return modifiers; - } - - /** - * Set the list of modifiers. - * - * @param modifiers a list of annotations - */ - void setModifiers(Annotation[] modifiers) { - this.modifiers = modifiers; - } - - /** - * Return the number of arguments this binding consumes. - * - * @return -1 if unknown or unavailable - */ - int getConsumedCount() { - return getBinding().getConsumedCount(this); - } - - /** - * Get whether this parameter is entered by the user. - * - * @return true if this parameter is entered by the user. - */ - boolean isUserInput() { - return getBinding().getBehavior(this) != BindingBehavior.PROVIDES; - } - - /** - * Get whether this parameter consumes non-flag arguments. - * - * @return true if this parameter consumes non-flag arguments - */ - boolean isNonFlagConsumer() { - return getBinding().getBehavior(this) != BindingBehavior.PROVIDES && !isValueFlag(); - } - - /** - * Validate this parameter and its binding. - */ - void validate(Method method, int parameterIndex) throws ParametricException { - // We can't have indeterminate consumers without @Switches otherwise - // it may screw up parameter processing for later bindings - BindingBehavior behavior = getBinding().getBehavior(this); - boolean indeterminate = (behavior == BindingBehavior.INDETERMINATE); - if (!isValueFlag() && indeterminate) { - throw new ParametricException( - "@Switch missing for indeterminate consumer\n\n" + - "Notably:\nFor the type " + type + ", the binding " + - getBinding().getClass().getCanonicalName() + - "\nmay or may not consume parameters (isIndeterminateConsumer(" + type + ") = true)" + - "\nand therefore @Switch(flag) is required for parameter #" + parameterIndex + " of \n" + - method.toGenericString()); - } - - // getConsumedCount() better return -1 if the BindingBehavior is not CONSUMES - if (behavior != BindingBehavior.CONSUMES && binding.getConsumedCount(this) != -1) { - throw new ParametricException( - "getConsumedCount() does not return -1 for binding " + - getBinding().getClass().getCanonicalName() + - "\neven though its behavior type is " + behavior.name() + - "\nfor parameter #" + parameterIndex + " of \n" + - method.toGenericString()); - } - - // getConsumedCount() should not return 0 if the BindingBehavior is not PROVIDES - if (behavior != BindingBehavior.PROVIDES && binding.getConsumedCount(this) == 0) { - throw new ParametricException( - "getConsumedCount() must not return 0 for binding " + - getBinding().getClass().getCanonicalName() + - "\nwhen its behavior type is " + behavior.name() + " and not PROVIDES " + - "\nfor parameter #" + parameterIndex + " of \n" + - method.toGenericString()); - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterException.java deleted file mode 100644 index 2fe681ba7..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParameterException.java +++ /dev/null @@ -1,43 +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 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.util.command.parametric; - -/** - * Thrown if there is an error with a parameter. - */ -public class ParameterException extends Exception { - - public ParameterException() { - super(); - } - - public ParameterException(String message) { - super(message); - } - - public ParameterException(Throwable cause) { - super(cause); - } - - public ParameterException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java deleted file mode 100644 index 422cd9982..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java +++ /dev/null @@ -1,230 +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 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.util.command.parametric; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.collect.ImmutableBiMap.Builder; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.worldedit.util.auth.Authorizer; -import com.sk89q.worldedit.util.auth.NullAuthorizer; -import com.sk89q.worldedit.util.command.CommandCallable; -import com.sk89q.worldedit.util.command.CommandCompleter; -import com.sk89q.worldedit.util.command.Dispatcher; -import com.sk89q.worldedit.util.command.NullCompleter; -import com.sk89q.worldedit.util.command.binding.PrimitiveBindings; -import com.sk89q.worldedit.util.command.binding.StandardBindings; -import com.sk89q.worldedit.util.command.binding.Switch; -import com.thoughtworks.paranamer.CachingParanamer; -import com.thoughtworks.paranamer.Paranamer; - -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Creates commands using annotations placed on methods and individual parameters of - * such methods. - * - * @see Command defines a command - * @see Switch defines a flag - */ -public class ParametricBuilder { - - private final Map bindings = new HashMap<>(); - private final Paranamer paranamer = new CachingParanamer(); - private final List invokeListeners = new ArrayList<>(); - private Authorizer authorizer = new NullAuthorizer(); - private CommandCompleter defaultCompleter = new NullCompleter(); - - /** - * Create a new builder. - * - *

This method will install {@link PrimitiveBindings} and - * {@link StandardBindings} and default bindings.

- */ - public ParametricBuilder() { - addBinding(new PrimitiveBindings()); - addBinding(new StandardBindings()); - } - - /** - * Add a binding for a given type or classifier (annotation). - * - *

Whenever a method parameter is encountered, a binding must be found for it - * so that it can be called later to consume the stack of arguments provided by - * the user and return an object that is later passed to - * {@link Method#invoke(Object, Object...)}.

- * - *

Normally, a {@link Type} is used to discern between different bindings, but - * if this is not specific enough, an annotation can be defined and used. This - * makes it a "classifier" and it will take precedence over the base type. For - * example, even if there is a binding that handles {@link String} parameters, - * a special {@code @MyArg} annotation can be assigned to a {@link String} - * parameter, which will cause the {@link Builder} to consult the {@link Binding} - * associated with {@code @MyArg} rather than with the binding for - * the {@link String} type.

- * - * @param binding the binding - * @param type a list of types (if specified) to override the binding's types - */ - public void addBinding(Binding binding, Type... type) { - if (type == null || type.length == 0) { - type = binding.getTypes(); - } - - for (Type t : type) { - bindings.put(t, binding); - } - } - - /** - * Attach an invocation listener. - * - *

Invocation handlers are called in order that their listeners are - * registered with a {@link ParametricBuilder}. It is not guaranteed that - * a listener may be called, in the case of a {@link CommandException} being - * thrown at any time before the appropriate listener or handler is called. - * It is possible for a - * {@link InvokeHandler#preInvoke(Object, Method, ParameterData[], Object[], CommandContext)} to - * be called for a invocation handler, but not the associated - * {@link InvokeHandler#postInvoke(Object, Method, ParameterData[], Object[], CommandContext)}.

- * - *

An example of an invocation listener is one to handle - * {@link CommandPermissions}, by first checking to see if permission is available - * in a {@link InvokeHandler#preInvoke(Object, Method, ParameterData[], Object[], CommandContext)} - * call. If permission is not found, then an appropriate {@link CommandException} - * can be thrown to cease invocation.

- * - * @param listener the listener - * @see InvokeHandler the handler - */ - public void addInvokeListener(InvokeListener listener) { - invokeListeners.add(listener); - } - - /** - * Build a list of commands from methods specially annotated with {@link Command} - * (and other relevant annotations) and register them all with the given - * {@link Dispatcher}. - * - * @param dispatcher the dispatcher to register commands with - * @param object the object contain the methods - * @throws ParametricException thrown if the commands cannot be registered - */ - public void registerMethodsAsCommands(Dispatcher dispatcher, Object object) throws ParametricException { - for (Method method : object.getClass().getDeclaredMethods()) { - Command definition = method.getAnnotation(Command.class); - if (definition != null) { - CommandCallable callable = build(object, method, definition); - dispatcher.registerCommand(callable, definition.aliases()); - } - } - } - - /** - * Build a {@link CommandCallable} for the given method. - * - * @param object the object to be invoked on - * @param method the method to invoke - * @param definition the command definition annotation - * @return the command executor - * @throws ParametricException thrown on an error - */ - private CommandCallable build(Object object, Method method, Command definition) - throws ParametricException { - return new ParametricCallable(this, object, method, definition); - } - - /** - * Get the object used to get method names on Java versions before 8 (assuming - * that Java 8 is given the ability to reliably reflect method names at runtime). - * - * @return the paranamer - */ - Paranamer getParanamer() { - return paranamer; - } - - /** - * Get the map of bindings. - * - * @return the map of bindings - */ - Map getBindings() { - return bindings; - } - - /** - * Get a list of invocation listeners. - * - * @return a list of invocation listeners - */ - List getInvokeListeners() { - return invokeListeners; - } - - /** - * Get the authorizer. - * - * @return the authorizer - */ - public Authorizer getAuthorizer() { - return authorizer; - } - - /** - * Set the authorizer. - * - * @param authorizer the authorizer - */ - public void setAuthorizer(Authorizer authorizer) { - checkNotNull(authorizer); - this.authorizer = authorizer; - } - - /** - * Get the default command suggestions provider that will be used if - * no suggestions are available. - * - * @return the default command completer - */ - public CommandCompleter getDefaultCompleter() { - return defaultCompleter; - } - - /** - * Set the default command suggestions provider that will be used if - * no suggestions are available. - * - * @param defaultCompleter the default command completer - */ - public void setDefaultCompleter(CommandCompleter defaultCompleter) { - checkNotNull(defaultCompleter); - this.defaultCompleter = defaultCompleter; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java deleted file mode 100644 index 39f47b20e..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java +++ /dev/null @@ -1,479 +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 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.util.command.parametric; - -import com.google.common.primitives.Chars; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.minecraft.util.commands.CommandLocals; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.CommandPermissionsException; -import com.sk89q.minecraft.util.commands.WrappedCommandException; -import com.sk89q.worldedit.util.command.CommandCallable; -import com.sk89q.worldedit.util.command.InvalidUsageException; -import com.sk89q.worldedit.util.command.MissingParameterException; -import com.sk89q.worldedit.util.command.Parameter; -import com.sk89q.worldedit.util.command.SimpleDescription; -import com.sk89q.worldedit.util.command.UnconsumedParameterException; -import com.sk89q.worldedit.util.command.binding.Switch; - -import java.lang.annotation.Annotation; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * The implementation of a {@link CommandCallable} for the {@link ParametricBuilder}. - */ -class ParametricCallable implements CommandCallable { - - private final ParametricBuilder builder; - private final Object object; - private final Method method; - private final ParameterData[] parameters; - private final Set valueFlags = new HashSet<>(); - private final boolean anyFlags; - private final Set legacyFlags = new HashSet<>(); - private final SimpleDescription description = new SimpleDescription(); - private final CommandPermissions commandPermissions; - - /** - * Create a new instance. - * - * @param builder the parametric builder - * @param object the object to invoke on - * @param method the method to invoke - * @param definition the command definition annotation - * @throws ParametricException thrown on an error - */ - ParametricCallable(ParametricBuilder builder, Object object, Method method, Command definition) throws ParametricException { - this.builder = builder; - this.object = object; - this.method = method; - - Annotation[][] annotations = method.getParameterAnnotations(); - String[] names = builder.getParanamer().lookupParameterNames(method, false); - Type[] types = method.getGenericParameterTypes(); - parameters = new ParameterData[types.length]; - List userParameters = new ArrayList<>(); - - // This helps keep tracks of @Nullables that appear in the middle of a list - // of parameters - int numOptional = 0; - - // Set permission hint - CommandPermissions permHint = method.getAnnotation(CommandPermissions.class); - if (permHint != null) { - description.setPermissions(Arrays.asList(permHint.value())); - } - - // Go through each parameter - for (int i = 0; i < types.length; i++) { - Type type = types[i]; - - ParameterData parameter = new ParameterData(); - parameter.setType(type); - parameter.setModifiers(annotations[i]); - - // Search for annotations - for (Annotation annotation : annotations[i]) { - if (annotation instanceof Switch) { - parameter.setFlag(((Switch) annotation).value(), type != boolean.class); - } else if (annotation instanceof Optional) { - parameter.setOptional(true); - String[] value = ((Optional) annotation).value(); - if (value.length > 0) { - parameter.setDefaultValue(value); - } - // Special annotation bindings - } else if (parameter.getBinding() == null) { - parameter.setBinding(builder.getBindings().get(annotation.annotationType())); - parameter.setClassifier(annotation); - } - } - - parameter.setName(names.length > 0 ? names[i] : generateName(type, parameter.getClassifier(), i)); - - // Track all value flags - if (parameter.isValueFlag()) { - valueFlags.add(parameter.getFlag()); - } - - // No special @annotation binding... let's check for the type - if (parameter.getBinding() == null) { - parameter.setBinding(builder.getBindings().get(type)); - - // Don't know how to parse for this type of value - if (parameter.getBinding() == null) { - throw new ParametricException("Don't know how to handle the parameter type '" + type + "' in\n" + method.toGenericString()); - } - } - - // Do some validation of this parameter - parameter.validate(method, i + 1); - - // Keep track of optional parameters - if (parameter.isOptional() && parameter.getFlag() == null) { - numOptional++; - } else { - if (numOptional > 0 && parameter.isNonFlagConsumer()) { - if (parameter.getConsumedCount() < 0) { - throw new ParametricException( - "Found an parameter using the binding " + - parameter.getBinding().getClass().getCanonicalName() + - "\nthat does not know how many arguments it consumes, but " + - "it follows an optional parameter\nMethod: " + - method.toGenericString()); - } - } - } - - parameters[i] = parameter; - - // Make a list of "real" parameters - if (parameter.isUserInput()) { - userParameters.add(parameter); - } - } - - // Gather legacy flags - anyFlags = definition.anyFlags(); - legacyFlags.addAll(Chars.asList(definition.flags().toCharArray())); - - // Finish description - description.setDescription(!definition.desc().isEmpty() ? definition.desc() : null); - description.setHelp(!definition.help().isEmpty() ? definition.help() : null); - description.overrideUsage(!definition.usage().isEmpty() ? definition.usage() : null); - - for (InvokeListener listener : builder.getInvokeListeners()) { - listener.updateDescription(object, method, parameters, description); - } - - // Set parameters - description.setParameters(userParameters); - - // Get permissions annotation - commandPermissions = method.getAnnotation(CommandPermissions.class); - } - - @Override - public Object call(String stringArguments, CommandLocals locals, String[] parentCommands) throws CommandException { - // Test permission - if (parentCommands.length != 0 && !testPermission(locals)) { - throw new CommandPermissionsException(); - } - - String calledCommand = parentCommands.length > 0 ? parentCommands[parentCommands.length - 1] : "_"; - String[] split = CommandContext.split(calledCommand + " " + stringArguments); - CommandContext context = new CommandContext(split, getValueFlags(), false, locals); - - // Provide help if -? is specified - if (context.hasFlag('?')) { - throw new InvalidUsageException(null, this, true); - } - - Object[] args = new Object[parameters.length]; - ContextArgumentStack arguments = new ContextArgumentStack(context); - ParameterData parameter = null; - - try { - // preProcess handlers - List handlers = new ArrayList<>(); - for (InvokeListener listener : builder.getInvokeListeners()) { - InvokeHandler handler = listener.createInvokeHandler(); - handlers.add(handler); - handler.preProcess(object, method, parameters, context); - } - - // Collect parameters - for (int i = 0; i < parameters.length; i++) { - parameter = parameters[i]; - - if (mayConsumeArguments(i, arguments)) { - // Parse the user input into a method argument - ArgumentStack usedArguments = getScopedContext(parameter, arguments); - - try { - args[i] = parameter.getBinding().bind(parameter, usedArguments, false); - } catch (MissingParameterException e) { - // Not optional? Then we can't execute this command - if (!parameter.isOptional()) { - throw e; - } - - args[i] = getDefaultValue(i, arguments); - } - } else { - args[i] = getDefaultValue(i, arguments); - } - } - - // Check for unused arguments - checkUnconsumed(arguments); - - // preInvoke handlers - for (InvokeHandler handler : handlers) { - handler.preInvoke(object, method, parameters, args, context); - } - - // Execute! - method.invoke(object, args); - - // postInvoke handlers - for (InvokeHandler handler : handlers) { - handler.postInvoke(handler, method, parameters, args, context); - } - } catch (MissingParameterException e) { - throw new InvalidUsageException("Too few parameters!", this); - } catch (UnconsumedParameterException e) { - throw new InvalidUsageException("Too many parameters! Unused parameters: " + e.getUnconsumed(), this); - } catch (ParameterException e) { - assert parameter != null; - String name = parameter.getName(); - - throw new InvalidUsageException("For parameter '" + name + "': " + e.getMessage(), this); - } catch (InvocationTargetException e) { - if (e.getCause() instanceof CommandException) { - throw (CommandException) e.getCause(); - } - throw new WrappedCommandException(e); - } catch (Throwable t) { - throw new WrappedCommandException(t); - } - - return true; - } - - @Override - public List getSuggestions(String arguments, CommandLocals locals) throws CommandException { - return builder.getDefaultCompleter().getSuggestions(arguments, locals); - } - - /** - * Get a list of value flags used by this command. - * - * @return a list of value flags - */ - public Set getValueFlags() { - return valueFlags; - } - - @Override - public SimpleDescription getDescription() { - return description; - } - - @Override - public boolean testPermission(CommandLocals locals) { - if (commandPermissions != null) { - for (String perm : commandPermissions.value()) { - if (builder.getAuthorizer().testPermission(locals, perm)) { - return true; - } - } - - return false; - } else { - return true; - } - } - - /** - * Get the right {@link ArgumentStack}. - * - * @param parameter the parameter - * @param existing the existing scoped context - * @return the context to use - */ - private static ArgumentStack getScopedContext(Parameter parameter, ArgumentStack existing) { - if (parameter.getFlag() != null) { - CommandContext context = existing.getContext(); - - if (parameter.isValueFlag()) { - return new StringArgumentStack(context, context.getFlag(parameter.getFlag()), false); - } else { - String v = context.hasFlag(parameter.getFlag()) ? "true" : "false"; - return new StringArgumentStack(context, v, true); - } - } - - return existing; - } - - /** - * Get whether a parameter is allowed to consume arguments. - * - * @param i the index of the parameter - * @param scoped the scoped context - * @return true if arguments may be consumed - */ - private boolean mayConsumeArguments(int i, ContextArgumentStack scoped) { - CommandContext context = scoped.getContext(); - ParameterData parameter = parameters[i]; - - // Flag parameters: Always consume - // Required non-flag parameters: Always consume - // Optional non-flag parameters: - // - Before required parameters: Consume if there are 'left over' args - // - At the end: Always consumes - - if (parameter.isOptional()) { - if (parameter.getFlag() != null) { - return !parameter.isValueFlag() || context.hasFlag(parameter.getFlag()); - } else { - int numberFree = context.argsLength() - scoped.position(); - for (int j = i; j < parameters.length; j++) { - if (parameters[j].isNonFlagConsumer() && !parameters[j].isOptional()) { - // We already checked if the consumed count was > -1 - // when we created this object - numberFree -= parameters[j].getConsumedCount(); - } - } - - // Skip this optional parameter - if (numberFree < 1) { - return false; - } - } - } - - return true; - } - - /** - * Get the default value for a parameter. - * - * @param i the index of the parameter - * @param scoped the scoped context - * @return a value - * @throws ParameterException on an error - * @throws CommandException on an error - */ - private Object getDefaultValue(int i, ContextArgumentStack scoped) throws ParameterException, CommandException, InvocationTargetException { - CommandContext context = scoped.getContext(); - ParameterData parameter = parameters[i]; - - String[] defaultValue = parameter.getDefaultValue(); - if (defaultValue != null) { - try { - return parameter.getBinding().bind(parameter, new StringArgumentStack(context, defaultValue, false), false); - } catch (MissingParameterException e) { - throw new ParametricException( - "The default value of the parameter using the binding " + - parameter.getBinding().getClass() + " in the method\n" + - method.toGenericString() + "\nis invalid"); - } - } - - return null; - } - - - /** - * Check to see if all arguments, including flag arguments, were consumed. - * - * @param scoped the argument scope - * @throws UnconsumedParameterException thrown if parameters were not consumed - */ - private void checkUnconsumed(ContextArgumentStack scoped) throws UnconsumedParameterException { - CommandContext context = scoped.getContext(); - String unconsumed; - String unconsumedFlags = getUnusedFlags(context); - - if ((unconsumed = scoped.getUnconsumed()) != null) { - throw new UnconsumedParameterException(unconsumed + " " + unconsumedFlags); - } - - if (unconsumedFlags != null) { - throw new UnconsumedParameterException(unconsumedFlags); - } - } - - /** - * Get any unused flag arguments. - * - * @param context the command context - */ - private String getUnusedFlags(CommandContext context) { - if (!anyFlags) { - Set unusedFlags = null; - for (char flag : context.getFlags()) { - boolean found = false; - - if (legacyFlags.contains(flag)) { - break; - } - - for (ParameterData parameter : parameters) { - Character paramFlag = parameter.getFlag(); - if (paramFlag != null && flag == paramFlag) { - found = true; - break; - } - } - - if (!found) { - if (unusedFlags == null) { - unusedFlags = new HashSet<>(); - } - unusedFlags.add(flag); - } - } - - if (unusedFlags != null) { - StringBuilder builder = new StringBuilder(); - for (Character flag : unusedFlags) { - builder.append("-").append(flag).append(" "); - } - - return builder.toString().trim(); - } - } - - return null; - } - - /** - * Generate a name for a parameter. - * - * @param type the type - * @param classifier the classifier - * @param index the index - * @return a generated name - */ - private static String generateName(Type type, Annotation classifier, int index) { - if (classifier != null) { - return classifier.annotationType().getSimpleName().toLowerCase(); - } else { - if (type instanceof Class) { - return ((Class) type).getSimpleName().toLowerCase(); - } else { - return "unknown" + index; - } - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricException.java deleted file mode 100644 index 346816330..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricException.java +++ /dev/null @@ -1,44 +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 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.util.command.parametric; - -/** - * Thrown if the {@link ParametricBuilder} can't build commands from - * an object for whatever reason. - */ -public class ParametricException extends RuntimeException { - - public ParametricException() { - super(); - } - - public ParametricException(String message, Throwable cause) { - super(message, cause); - } - - public ParametricException(String message) { - super(message); - } - - public ParametricException(Throwable cause) { - super(cause); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/StringArgumentStack.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/StringArgumentStack.java deleted file mode 100644 index 9d4142adc..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/StringArgumentStack.java +++ /dev/null @@ -1,128 +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 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.util.command.parametric; - -import com.sk89q.minecraft.util.commands.CommandContext; -import com.sk89q.util.StringUtil; -import com.sk89q.worldedit.util.command.MissingParameterException; - -/** - * A virtual scope that does not actually read from the underlying - * {@link CommandContext}. - */ -public class StringArgumentStack implements ArgumentStack { - - private final boolean nonNullBoolean; - private final CommandContext context; - private final String[] arguments; - private int index = 0; - - /** - * Create a new instance using the given context. - * - * @param context the context - * @param arguments a list of arguments - * @param nonNullBoolean true to have {@link #nextBoolean()} return false instead of null - */ - public StringArgumentStack( - CommandContext context, String[] arguments, boolean nonNullBoolean) { - this.context = context; - this.arguments = arguments; - this.nonNullBoolean = nonNullBoolean; - } - - /** - * Create a new instance using the given context. - * - * @param context the context - * @param arguments an argument string to be parsed - * @param nonNullBoolean true to have {@link #nextBoolean()} return false instead of null - */ - public StringArgumentStack( - CommandContext context, String arguments, boolean nonNullBoolean) { - this.context = context; - this.arguments = CommandContext.split(arguments); - this.nonNullBoolean = nonNullBoolean; - } - - @Override - public String next() throws ParameterException { - try { - return arguments[index++]; - } catch (ArrayIndexOutOfBoundsException e) { - throw new MissingParameterException(); - } - } - - @Override - public Integer nextInt() throws ParameterException { - try { - return Integer.parseInt(next()); - } catch (NumberFormatException e) { - throw new ParameterException( - "Expected a number, got '" + context.getString(index - 1) + "'"); - } - } - - @Override - public Double nextDouble() throws ParameterException { - try { - return Double.parseDouble(next()); - } catch (NumberFormatException e) { - throw new ParameterException( - "Expected a number, got '" + context.getString(index - 1) + "'"); - } - } - - @Override - public Boolean nextBoolean() throws ParameterException { - try { - return next().equalsIgnoreCase("true"); - } catch (IndexOutOfBoundsException e) { - if (nonNullBoolean) { // Special case - return false; - } - - throw new MissingParameterException(); - } - } - - @Override - public String remaining() throws ParameterException { - try { - String value = StringUtil.joinString(arguments, " ", index); - markConsumed(); - return value; - } catch (IndexOutOfBoundsException e) { - throw new MissingParameterException(); - } - } - - @Override - public void markConsumed() { - index = arguments.length; - } - - @Override - public CommandContext getContext() { - return context; - } - -} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java index 07cb23fba..dcaeca0b3 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java @@ -30,8 +30,6 @@ import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; import com.sk89q.worldedit.sponge.config.SpongeConfiguration; -import com.sk89q.worldedit.util.command.CommandMapping; -import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; import org.enginehub.piston.Command; @@ -44,6 +42,7 @@ import org.spongepowered.api.entity.EntityType; import org.spongepowered.api.scheduler.Task; import org.spongepowered.api.world.Location; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; @@ -51,8 +50,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import javax.annotation.Nullable; - import static java.util.stream.Collectors.toList; class SpongePlatform extends AbstractPlatform implements MultiUserPlatform { From fb4fb980e07503939238a049bc6cce798dcb5835 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 30 Apr 2019 15:03:18 -0700 Subject: [PATCH 101/366] Condense some command packages --- .../com/sk89q/worldedit/command/ApplyBrushCommands.java | 2 +- .../com/sk89q/worldedit/command/PaintBrushCommands.java | 2 +- .../sk89q/worldedit/command/util/AsyncCommandHelper.java | 2 +- .../worldedit/command/util/MessageFutureCallback.java | 2 +- .../sk89q/worldedit/command/util/PrintCommandHelp.java | 4 ++-- .../extension/platform/PlatformCommandManager.java | 8 ++++---- .../{util => internal}/command/CommandArgParser.java | 2 +- .../command/CommandRegistrationHandler.java | 2 +- .../worldedit/{util => internal}/command/CommandUtil.java | 2 +- .../command/exception}/ExceptionConverter.java | 2 +- .../command/exception}/ExceptionConverterHelper.java | 3 +-- .../command/exception}/ExceptionMatch.java | 2 +- .../{ => exception}/WorldEditExceptionConverter.java | 4 +--- .../util/formatting/component/CommandUsageBox.java | 4 ++-- .../sk89q/worldedit/util/paste/ActorCallbackPaste.java | 2 +- 15 files changed, 20 insertions(+), 23 deletions(-) rename worldedit-core/src/main/java/com/sk89q/worldedit/{util => internal}/command/CommandArgParser.java (98%) rename worldedit-core/src/main/java/com/sk89q/worldedit/{util => internal}/command/CommandRegistrationHandler.java (97%) rename worldedit-core/src/main/java/com/sk89q/worldedit/{util => internal}/command/CommandUtil.java (97%) rename worldedit-core/src/main/java/com/sk89q/worldedit/{util/command/parametric => internal/command/exception}/ExceptionConverter.java (97%) rename worldedit-core/src/main/java/com/sk89q/worldedit/{util/command/parametric => internal/command/exception}/ExceptionConverterHelper.java (97%) rename worldedit-core/src/main/java/com/sk89q/worldedit/{util/command/parametric => internal/command/exception}/ExceptionMatch.java (95%) rename worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/{ => exception}/WorldEditExceptionConverter.java (97%) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java index cfab5fbae..f9ceadd3e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java @@ -35,7 +35,7 @@ import com.sk89q.worldedit.function.factory.Apply; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.factory.RegionFactory; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.command.CommandRegistrationHandler; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import org.enginehub.piston.CommandManager; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java index 4f4064827..cc53ec5b8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java @@ -35,7 +35,7 @@ import com.sk89q.worldedit.function.factory.Paint; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.factory.RegionFactory; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.util.command.CommandRegistrationHandler; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import org.enginehub.piston.CommandManager; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java index 7557b0834..842cd5752 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java @@ -24,7 +24,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; +import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; import com.sk89q.worldedit.util.task.FutureForwardingTask; import com.sk89q.worldedit.util.task.Supervisor; import com.sk89q.worldedit.world.World; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java index 58b25770d..2a330259e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java @@ -23,7 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.util.concurrent.FutureCallback; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; +import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; import org.enginehub.piston.exception.CommandException; import javax.annotation.Nullable; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java index df57539ba..aa911b705 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -36,8 +36,8 @@ import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.sk89q.worldedit.util.command.CommandUtil.byCleanName; -import static com.sk89q.worldedit.util.command.CommandUtil.getSubCommands; +import static com.sk89q.worldedit.internal.command.CommandUtil.byCleanName; +import static com.sk89q.worldedit.internal.command.CommandUtil.getSubCommands; import static java.util.stream.Collectors.toList; /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index f1f7380a4..65df87e16 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -86,12 +86,12 @@ import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.command.CommandLoggingHandler; -import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter; +import com.sk89q.worldedit.internal.command.exception.WorldEditExceptionConverter; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; -import com.sk89q.worldedit.util.command.CommandArgParser; -import com.sk89q.worldedit.util.command.CommandRegistrationHandler; -import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; +import com.sk89q.worldedit.internal.command.CommandArgParser; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java similarity index 98% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java index 5c414d08a..e3605b6f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandArgParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.util.command; +package com.sk89q.worldedit.internal.command; import java.util.stream.Stream; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandRegistrationHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java similarity index 97% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandRegistrationHandler.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java index 8e243be98..dec0d6e24 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandRegistrationHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.util.command; +package com.sk89q.worldedit.internal.command; import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.WorldEdit; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java similarity index 97% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java index 3d86fbfb9..861c7926d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.util.command; +package com.sk89q.worldedit.internal.command; import com.sk89q.worldedit.extension.platform.PlatformCommandManager; import org.enginehub.piston.Command; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverter.java similarity index 97% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverter.java index e943cd6e9..27a494175 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverter.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.util.command.parametric; +package com.sk89q.worldedit.internal.command.exception; import org.enginehub.piston.exception.CommandException; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java similarity index 97% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java index 039bd4cde..99a9bce68 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionConverterHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java @@ -17,10 +17,9 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.util.command.parametric; +package com.sk89q.worldedit.internal.command.exception; import com.google.common.collect.ImmutableList; -import com.sk89q.minecraft.util.commands.WrappedCommandException; import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.CommandExecutionException; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionMatch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionMatch.java similarity index 95% rename from worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionMatch.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionMatch.java index 619bc9d46..99acf81fa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/command/parametric/ExceptionMatch.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionMatch.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.util.command.parametric; +package com.sk89q.worldedit.internal.command.exception; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java similarity index 97% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java index 3dfafe349..a0100fc4c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/WorldEditExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.command; +package com.sk89q.worldedit.internal.command.exception; import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.DisallowedItemException; @@ -35,8 +35,6 @@ import com.sk89q.worldedit.command.InsufficientArgumentsException; import com.sk89q.worldedit.command.tool.InvalidToolBindException; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.regions.RegionOperationException; -import com.sk89q.worldedit.util.command.parametric.ExceptionConverterHelper; -import com.sk89q.worldedit.util.command.parametric.ExceptionMatch; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException; import com.sk89q.worldedit.util.io.file.FilenameResolutionException; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index d2a97fcf2..46347d107 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -30,8 +30,8 @@ import java.util.Map; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.util.command.CommandUtil.byCleanName; -import static com.sk89q.worldedit.util.command.CommandUtil.getSubCommands; +import static com.sk89q.worldedit.internal.command.CommandUtil.byCleanName; +import static com.sk89q.worldedit.internal.command.CommandUtil.getSubCommands; /** * A box to describe usage of a command. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java index 4c86e6866..0509275f6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java @@ -24,7 +24,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.sk89q.worldedit.command.util.AsyncCommandHelper; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.util.command.parametric.ExceptionConverter; +import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; import com.sk89q.worldedit.util.task.Supervisor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; From 13a8c480e384afec71ff76ff7a152e5e18e6d3cf Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 1 May 2019 00:03:37 -0700 Subject: [PATCH 102/366] Insert Locale.ROOT into all case change methods --- .../ConfigurationPermissionsResolver.java | 11 ++++++----- .../wepif/FlatFilePermissionsResolver.java | 11 ++++++----- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 13 +++++++------ .../sk89q/worldedit/bukkit/BukkitPlayer.java | 5 +++-- .../worldedit/bukkit/WorldEditPlugin.java | 7 +++++-- .../sk89q/wepif/TestOfflinePermissible.java | 17 +++++++++-------- .../java/com/sk89q/jnbt/ByteArrayTag.java | 4 +++- .../main/java/com/sk89q/jnbt/IntArrayTag.java | 4 +++- .../java/com/sk89q/jnbt/LongArrayTag.java | 4 +++- .../util/commands/CommandsManager.java | 5 +++-- .../main/java/com/sk89q/util/StringUtil.java | 17 +++++++++-------- .../java/com/sk89q/worldedit/WorldEdit.java | 5 +++-- .../sk89q/worldedit/blocks/ClothColor.java | 3 ++- .../factory/parser/DefaultBlockParser.java | 7 ++++--- .../factory/parser/DefaultItemParser.java | 4 +++- .../parser/mask/BlockCategoryMaskParser.java | 4 +++- .../pattern/BlockCategoryPatternParser.java | 3 ++- .../platform/PlatformCommandManager.java | 3 ++- .../clipboard/io/MCEditSchematicReader.java | 5 +++-- .../sk89q/worldedit/registry/Registry.java | 5 +++-- .../registry/state/DirectionalProperty.java | 3 ++- .../sk89q/worldedit/util/TreeGenerator.java | 3 ++- .../util/function/LevenshteinDistance.java | 7 ++++--- .../world/block/BlockStateHolder.java | 9 ++++++--- .../worldedit/world/snapshot/Snapshot.java | 19 +++++++++++-------- .../world/snapshot/SnapshotRepository.java | 17 ++++++++++++----- 26 files changed, 119 insertions(+), 76 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java b/worldedit-bukkit/src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java index d61674c1e..bdf1ba0ba 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java @@ -26,6 +26,7 @@ import org.bukkit.OfflinePlayer; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -102,8 +103,8 @@ public class ConfigurationPermissionsResolver implements PermissionsResolver { } } - userPermissionsCache.put(key.toLowerCase(), permsCache); - userGroups.put(key.toLowerCase(), new HashSet<>(groups)); + userPermissionsCache.put(key.toLowerCase(Locale.ROOT), permsCache); + userGroups.put(key.toLowerCase(Locale.ROOT), new HashSet<>(groups)); } } } @@ -117,7 +118,7 @@ public class ConfigurationPermissionsResolver implements PermissionsResolver { } } - Set perms = userPermissionsCache.get(player.toLowerCase()); + Set perms = userPermissionsCache.get(player.toLowerCase(Locale.ROOT)); if (perms == null) { return defaultPermissionsCache.contains(permission) || defaultPermissionsCache.contains("*"); @@ -134,7 +135,7 @@ public class ConfigurationPermissionsResolver implements PermissionsResolver { @Override public boolean inGroup(String player, String group) { - Set groups = userGroups.get(player.toLowerCase()); + Set groups = userGroups.get(player.toLowerCase(Locale.ROOT)); if (groups == null) { return false; } @@ -144,7 +145,7 @@ public class ConfigurationPermissionsResolver implements PermissionsResolver { @Override public String[] getGroups(String player) { - Set groups = userGroups.get(player.toLowerCase()); + Set groups = userGroups.get(player.toLowerCase(Locale.ROOT)); if (groups == null) { return new String[0]; } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/wepif/FlatFilePermissionsResolver.java b/worldedit-bukkit/src/main/java/com/sk89q/wepif/FlatFilePermissionsResolver.java index 9b5229cf3..242a86f45 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/wepif/FlatFilePermissionsResolver.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/wepif/FlatFilePermissionsResolver.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -159,8 +160,8 @@ public class FlatFilePermissionsResolver implements PermissionsResolver { } } - userPermissionsCache.put(key.toLowerCase(), permsCache); - userGroups.put(key.toLowerCase(), new HashSet<>(Arrays.asList(groups))); + userPermissionsCache.put(key.toLowerCase(Locale.ROOT), permsCache); + userGroups.put(key.toLowerCase(Locale.ROOT), new HashSet<>(Arrays.asList(groups))); } } } catch (IOException e) { @@ -184,7 +185,7 @@ public class FlatFilePermissionsResolver implements PermissionsResolver { } } - Set perms = userPermissionsCache.get(player.toLowerCase()); + Set perms = userPermissionsCache.get(player.toLowerCase(Locale.ROOT)); if (perms == null) { return defaultPermissionsCache.contains(permission) || defaultPermissionsCache.contains("*"); @@ -201,13 +202,13 @@ public class FlatFilePermissionsResolver implements PermissionsResolver { @Override public boolean inGroup(String player, String group) { - Set groups = userGroups.get(player.toLowerCase()); + Set groups = userGroups.get(player.toLowerCase(Locale.ROOT)); return groups != null && groups.contains(group); } @Override public String[] getGroups(String player) { - Set groups = userGroups.get(player.toLowerCase()); + Set groups = userGroups.get(player.toLowerCase(Locale.ROOT)); if (groups == null) { return new String[0]; } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index c76c854d3..d02bd1abc 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -53,6 +53,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -278,7 +279,7 @@ public class BukkitAdapter { if (!itemType.getId().startsWith("minecraft:")) { throw new IllegalArgumentException("Bukkit only supports Minecraft items"); } - return Material.getMaterial(itemType.getId().substring(10).toUpperCase()); + return Material.getMaterial(itemType.getId().substring(10).toUpperCase(Locale.ROOT)); } /** @@ -292,7 +293,7 @@ public class BukkitAdapter { if (!blockType.getId().startsWith("minecraft:")) { throw new IllegalArgumentException("Bukkit only supports Minecraft blocks"); } - return Material.getMaterial(blockType.getId().substring(10).toUpperCase()); + return Material.getMaterial(blockType.getId().substring(10).toUpperCase(Locale.ROOT)); } /** @@ -303,7 +304,7 @@ public class BukkitAdapter { */ public static GameMode adapt(org.bukkit.GameMode gameMode) { checkNotNull(gameMode); - return GameModes.get(gameMode.name().toLowerCase()); + return GameModes.get(gameMode.name().toLowerCase(Locale.ROOT)); } /** @@ -313,7 +314,7 @@ public class BukkitAdapter { * @return WorldEdit BiomeType */ public static BiomeType adapt(Biome biome) { - return BiomeTypes.get(biome.name().toLowerCase()); + return BiomeTypes.get(biome.name().toLowerCase(Locale.ROOT)); } public static Biome adapt(BiomeType biomeType) { @@ -321,7 +322,7 @@ public class BukkitAdapter { throw new IllegalArgumentException("Bukkit only supports vanilla biomes"); } try { - return Biome.valueOf(biomeType.getId().substring(10).toUpperCase()); + return Biome.valueOf(biomeType.getId().substring(10).toUpperCase(Locale.ROOT)); } catch (IllegalArgumentException e) { return null; } @@ -334,7 +335,7 @@ public class BukkitAdapter { * @return WorldEdit EntityType */ public static EntityType adapt(org.bukkit.entity.EntityType entityType) { - return EntityTypes.get(entityType.getName().toLowerCase()); + return EntityTypes.get(entityType.getName().toLowerCase(Locale.ROOT)); } public static org.bukkit.entity.EntityType adapt(EntityType entityType) { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index c0dc5c7e2..b5cd6bd37 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -44,6 +44,7 @@ import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.Locale; import java.util.UUID; import javax.annotation.Nullable; @@ -149,12 +150,12 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public GameMode getGameMode() { - return GameModes.get(player.getGameMode().name().toLowerCase()); + return GameModes.get(player.getGameMode().name().toLowerCase(Locale.ROOT)); } @Override public void setGameMode(GameMode gameMode) { - player.setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase())); + player.setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase(Locale.ROOT))); } @Override 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 99652499d..f53223a53 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 @@ -66,6 +66,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.jar.JarFile; import java.util.logging.Level; @@ -133,7 +134,8 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { public void setupRegistries() { // Biome for (Biome biome : Biome.values()) { - BiomeType.REGISTRY.register("minecraft:" + biome.name().toLowerCase(), new BiomeType("minecraft:" + biome.name().toLowerCase())); + String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT); + BiomeType.REGISTRY.register("minecraft:" + lowerCaseBiomeName, new BiomeType("minecraft:" + lowerCaseBiomeName)); } // Block & Item for (Material material : Material.values()) { @@ -167,7 +169,8 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { for (org.bukkit.entity.EntityType entityType : org.bukkit.entity.EntityType.values()) { String mcid = entityType.getName(); if (mcid != null) { - EntityType.REGISTRY.register("minecraft:" + mcid.toLowerCase(), new EntityType("minecraft:" + mcid.toLowerCase())); + String lowerCaseMcId = mcid.toLowerCase(Locale.ROOT); + EntityType.REGISTRY.register("minecraft:" + lowerCaseMcId, new EntityType("minecraft:" + lowerCaseMcId)); } } } diff --git a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java index 21c83228f..bec6d52d4 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java +++ b/worldedit-bukkit/src/test/java/com/sk89q/wepif/TestOfflinePermissible.java @@ -30,6 +30,7 @@ import org.bukkit.plugin.Plugin; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -37,7 +38,7 @@ import java.util.UUID; public class TestOfflinePermissible implements OfflinePlayer, Permissible { private boolean op; private UUID randomUuid = UUID.randomUUID(); - + private final Map assignedPermissions = new HashMap<>(); @Override @@ -52,7 +53,7 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible { @Override public boolean isPermissionSet(String s) { - return assignedPermissions.containsKey(s.toLowerCase()); + return assignedPermissions.containsKey(s.toLowerCase(Locale.ROOT)); } @Override @@ -63,7 +64,7 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible { @Override public boolean hasPermission(String s) { if (isPermissionSet(s)) { - return assignedPermissions.get(s.toLowerCase()); + return assignedPermissions.get(s.toLowerCase(Locale.ROOT)); } return false; } @@ -111,19 +112,19 @@ public class TestOfflinePermissible implements OfflinePlayer, Permissible { } return ret; } - + public void setPermission(String permission, boolean value) { - assignedPermissions.put(permission.toLowerCase(), value); + assignedPermissions.put(permission.toLowerCase(Locale.ROOT), value); } - + public void unsetPermission(String permission) { - assignedPermissions.remove(permission.toLowerCase()); + assignedPermissions.remove(permission.toLowerCase(Locale.ROOT)); } public void clearPermissions() { assignedPermissions.clear(); } - + // -- Unneeded OfflinePlayer methods @Override 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 b4fb9dc52..791ee97ea 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/ByteArrayTag.java @@ -19,6 +19,8 @@ package com.sk89q.jnbt; +import java.util.Locale; + /** * The {@code TAG_Byte_Array} tag. */ @@ -45,7 +47,7 @@ public final class ByteArrayTag extends Tag { public String toString() { StringBuilder hex = new StringBuilder(); for (byte b : value) { - String hexDigits = Integer.toHexString(b).toUpperCase(); + String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ROOT); if (hexDigits.length() == 1) { hex.append("0"); } 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 7c5e49603..c9683391f 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/IntArrayTag.java @@ -19,6 +19,8 @@ package com.sk89q.jnbt; +import java.util.Locale; + import static com.google.common.base.Preconditions.checkNotNull; /** @@ -48,7 +50,7 @@ public final class IntArrayTag extends Tag { public String toString() { StringBuilder hex = new StringBuilder(); for (int b : value) { - String hexDigits = Integer.toHexString(b).toUpperCase(); + String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ROOT); if (hexDigits.length() == 1) { hex.append("0"); } 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 30dad0cc3..10b8feb94 100644 --- a/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java +++ b/worldedit-core/src/main/java/com/sk89q/jnbt/LongArrayTag.java @@ -19,6 +19,8 @@ package com.sk89q.jnbt; +import java.util.Locale; + import static com.google.common.base.Preconditions.checkNotNull; /** @@ -48,7 +50,7 @@ public class LongArrayTag extends Tag { public String toString() { StringBuilder hex = new StringBuilder(); for (long b : value) { - String hexDigits = Long.toHexString(b).toUpperCase(); + String hexDigits = Long.toHexString(b).toUpperCase(Locale.ROOT); if (hexDigits.length() == 1) { hex.append("0"); } diff --git a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java index 5263d3aba..b6aa385c8 100644 --- a/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java +++ b/worldedit-core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -254,7 +255,7 @@ public abstract class CommandsManager { * @return true if the command exists */ public boolean hasCommand(String command) { - return commands.get(null).containsKey(command.toLowerCase()); + return commands.get(null).containsKey(command.toLowerCase(Locale.ROOT)); } /** @@ -434,7 +435,7 @@ public abstract class CommandsManager { String cmdName = args[level]; Map map = commands.get(parent); - Method method = map.get(cmdName.toLowerCase()); + Method method = map.get(cmdName.toLowerCase(Locale.ROOT)); if (method == null) { if (parent == null) { // Root 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 2571f71f9..80792b846 100644 --- a/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java @@ -22,6 +22,7 @@ package com.sk89q.util; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Locale; import java.util.Map; /** @@ -34,7 +35,7 @@ public final class StringUtil { /** * Trim a string if it is longer than a certain length. - * + * * @param str the stirng * @param len the length to trim to * @return a new string @@ -49,7 +50,7 @@ public final class StringUtil { /** * Join an array of strings into a string. - * + * * @param str the string array * @param delimiter the delimiter * @param initialIndex the initial index to start form @@ -68,7 +69,7 @@ public final class StringUtil { /** * Join an array of strings into a string. - * + * * @param str the string array * @param delimiter the delimiter * @param initialIndex the initial index to start form @@ -92,7 +93,7 @@ public final class StringUtil { /** * Join an array of strings into a string. - * + * * @param str the string array * @param delimiter the delimiter * @return a new string @@ -103,7 +104,7 @@ public final class StringUtil { /** * Join an array of strings into a string. - * + * * @param str an array of objects * @param delimiter the delimiter * @param initialIndex the initial index to start form @@ -122,7 +123,7 @@ public final class StringUtil { /** * Join an array of strings into a string. - * + * * @param str a list of integers * @param delimiter the delimiter * @param initialIndex the initial index to start form @@ -219,7 +220,7 @@ public final class StringUtil { * calculated). (Note that the arrays aren't really copied anymore, just * switched...this is clearly much better than cloning an array or doing * a System.arraycopy() each time through the outer loop.) - * + * * Effectively, the difference between the two implementations is this * one does not cause an out of memory condition when calculating the LD * over two very large strings. @@ -274,7 +275,7 @@ public final class StringUtil { } public static > T lookup(Map lookup, String name, boolean fuzzy) { - String testName = name.replaceAll("[ _]", "").toLowerCase(); + String testName = name.replaceAll("[ _]", "").toLowerCase(Locale.ROOT); T type = lookup.get(testName); if (type != null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index 205cfde5f..38c7cbd26 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -72,6 +72,7 @@ import java.nio.file.Paths; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import static com.sk89q.worldedit.event.platform.Interaction.HIT; @@ -403,7 +404,7 @@ public final class WorldEdit { * @throws UnknownDirectionException thrown if the direction is not known */ public BlockVector3 getDirection(Player player, String dirStr) throws UnknownDirectionException { - dirStr = dirStr.toLowerCase(); + dirStr = dirStr.toLowerCase(Locale.ROOT); final Direction dir = getPlayerDirection(player, dirStr); @@ -424,7 +425,7 @@ public final class WorldEdit { * @throws UnknownDirectionException thrown if the direction is not known */ public BlockVector3 getDiagonalDirection(Player player, String dirStr) throws UnknownDirectionException { - dirStr = dirStr.toLowerCase(); + dirStr = dirStr.toLowerCase(Locale.ROOT); final Direction dir = getPlayerDirection(player, dirStr); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java index dd3ba1fc2..64719c113 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.blocks; import java.util.EnumSet; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import javax.annotation.Nullable; @@ -84,7 +85,7 @@ public enum ClothColor { */ @Nullable public static ClothColor lookup(String name) { - return lookup.get(name.toLowerCase()); + return lookup.get(name.toLowerCase(Locale.ROOT)); } /** 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 72bf195da..a103318ef 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 @@ -49,6 +49,7 @@ import com.sk89q.worldedit.world.block.FuzzyBlockState; import com.sk89q.worldedit.world.registry.LegacyMapper; import java.util.HashMap; +import java.util.Locale; import java.util.Map; /** @@ -107,7 +108,7 @@ public class DefaultBlockParser extends InputParser { * @return Mapped string */ private String woolMapper(String string) { - switch (string.toLowerCase()) { + switch (string.toLowerCase(Locale.ROOT)) { case "white": return BlockTypes.WHITE_WOOL.getId(); case "black": @@ -272,7 +273,7 @@ public class DefaultBlockParser extends InputParser { blockStates.putAll(blockInHand.getStates()); } else { // Attempt to lookup a block from ID or name. - blockType = BlockTypes.get(typeString.toLowerCase()); + blockType = BlockTypes.get(typeString.toLowerCase(Locale.ROOT)); if (blockType == null) { throw new NoMatchException("Does not match a valid block type: '" + input + "'"); @@ -323,7 +324,7 @@ public class DefaultBlockParser extends InputParser { if (blockAndExtraData.length > 1) { String mobName = blockAndExtraData[1]; for (MobType mobType : MobType.values()) { - if (mobType.getName().toLowerCase().equals(mobName.toLowerCase())) { + if (mobType.getName().toLowerCase(Locale.ROOT).equals(mobName.toLowerCase(Locale.ROOT))) { mobName = mobType.getName(); break; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java index f6c396b93..13c382cac 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java @@ -28,6 +28,8 @@ import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; +import java.util.Locale; + public class DefaultItemParser extends InputParser { public DefaultItemParser(WorldEdit worldEdit) { @@ -53,7 +55,7 @@ public class DefaultItemParser extends InputParser { } if (item == null) { - ItemType type = ItemTypes.get(input.toLowerCase()); + ItemType type = ItemTypes.get(input.toLowerCase(Locale.ROOT)); if (type != null) { item = new BaseItem(type); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java index ec3c65b5c..8745e60ca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java @@ -28,6 +28,8 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.world.block.BlockCategory; +import java.util.Locale; + public class BlockCategoryMaskParser extends InputParser { public BlockCategoryMaskParser(WorldEdit worldEdit) { @@ -41,7 +43,7 @@ public class BlockCategoryMaskParser extends InputParser { } // This means it's a tag mask. - BlockCategory category = BlockCategory.REGISTRY.get(input.substring(2).toLowerCase()); + BlockCategory category = BlockCategory.REGISTRY.get(input.substring(2).toLowerCase(Locale.ROOT)); if (category == null) { throw new InputParseException("Unrecognised tag '" + input.substring(2) + '\''); } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java index b2e9672f5..769394146 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java @@ -30,6 +30,7 @@ import com.sk89q.worldedit.world.block.BlockCategory; import com.sk89q.worldedit.world.block.BlockType; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.stream.Collectors; @@ -49,7 +50,7 @@ public class BlockCategoryPatternParser extends InputParser { if (!input.startsWith("##")) { return null; } - String tag = input.substring(2).toLowerCase(); + String tag = input.substring(2).toLowerCase(Locale.ROOT); boolean anyState = false; if (tag.startsWith("*")) { tag = tag.substring(1); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 65df87e16..0e6420c4d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -123,6 +123,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.util.List; +import java.util.Locale; import java.util.Optional; import java.util.function.Consumer; import java.util.logging.FileHandler; @@ -425,7 +426,7 @@ public final class PlatformCommandManager { split = newSplit; } - String searchCmd = split[0].toLowerCase(); + String searchCmd = split[0].toLowerCase(Locale.ROOT); // Try to detect the command if (!commandManager.containsCommand(searchCmd)) { 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 71005ad00..dc99d66dc 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 @@ -56,6 +56,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -261,7 +262,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { Location location = NBTConversions.toLocation(clipboard, compound.getListTag("Pos"), compound.getListTag("Rotation")); if (!id.isEmpty()) { - EntityType entityType = EntityTypes.get(id.toLowerCase()); + EntityType entityType = EntityTypes.get(id.toLowerCase(Locale.ROOT)); if (entityType != null) { for (EntityNBTCompatibilityHandler compatibilityHandler : ENTITY_COMPATIBILITY_HANDLERS) { if (compatibilityHandler.isAffectedEntity(entityType, compound)) { @@ -271,7 +272,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { BaseEntity state = new BaseEntity(entityType, compound); clipboard.createEntity(location, state); } else { - log.warn("Unknown entity when pasting schematic: " + id.toLowerCase()); + log.warn("Unknown entity when pasting schematic: " + id.toLowerCase(Locale.ROOT)); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java index e7d7e9e58..8d8bf46c4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -44,14 +45,14 @@ public class Registry implements Iterable { } public @Nullable V get(final String key) { - checkState(key.equals(key.toLowerCase()), "key must be lowercase"); + checkState(key.equals(key.toLowerCase(Locale.ROOT)), "key must be lowercase"); return this.map.get(key); } public V register(final String key, final V value) { requireNonNull(key, "key"); requireNonNull(value, "value"); - checkState(key.equals(key.toLowerCase()), "key must be lowercase"); + checkState(key.equals(key.toLowerCase(Locale.ROOT)), "key must be lowercase"); checkState(!this.map.containsKey(key), "key '%s' already has an associated %s", key, this.name); this.map.put(key, value); return value; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/DirectionalProperty.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/DirectionalProperty.java index 32c0e1435..97f293d57 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/DirectionalProperty.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/state/DirectionalProperty.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.registry.state; import com.sk89q.worldedit.util.Direction; import java.util.List; +import java.util.Locale; import javax.annotation.Nullable; @@ -34,7 +35,7 @@ public class DirectionalProperty extends AbstractProperty { @Nullable @Override public Direction getValueFor(final String string) { - Direction direction = Direction.valueOf(string.toUpperCase()); + Direction direction = Direction.valueOf(string.toUpperCase(Locale.ROOT)); if (!getValues().contains(direction)) { throw new IllegalArgumentException("Invalid direction value: " + string + ". Must be in " + getValues().toString()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java index d4845c5b8..ad9b798b1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TreeGenerator.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Random; import java.util.Set; @@ -161,7 +162,7 @@ public class TreeGenerator { */ @Nullable public static TreeType lookup(String name) { - return lookup.get(name.toLowerCase()); + return lookup.get(name.toLowerCase(Locale.ROOT)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java index 1020d92cd..12f7492ec 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/function/LevenshteinDistance.java @@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Function; +import java.util.Locale; import java.util.regex.Pattern; import javax.annotation.Nullable; @@ -60,7 +61,7 @@ public class LevenshteinDistance implements Function { checkNotNull(baseString); this.caseSensitive = caseSensitive; this.replacePattern = replacePattern; - baseString = caseSensitive ? baseString : baseString.toLowerCase(); + baseString = caseSensitive ? baseString : baseString.toLowerCase(Locale.ROOT); baseString = replacePattern != null ? replacePattern.matcher(baseString).replaceAll("") : baseString; this.baseString = baseString; } @@ -79,7 +80,7 @@ public class LevenshteinDistance implements Function { if (caseSensitive) { return distance(baseString, input); } else { - return distance(baseString, input.toLowerCase()); + return distance(baseString, input.toLowerCase(Locale.ROOT)); } } @@ -189,5 +190,5 @@ public class LevenshteinDistance implements Function { // actually has the most recent cost counts return p[n]; } - + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java index 74ea9760f..481ee1d63 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.world.block; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.registry.state.Property; +import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; @@ -92,9 +93,11 @@ public interface BlockStateHolder> { if (getStates().isEmpty()) { return this.getBlockType().getId(); } else { - String properties = - getStates().entrySet().stream().map(entry -> entry.getKey().getName() + "=" + entry.getValue().toString().toLowerCase()).collect(Collectors.joining( - ",")); + String properties = getStates().entrySet().stream() + .map(entry -> entry.getKey().getName() + + "=" + + entry.getValue().toString().toLowerCase(Locale.ROOT)) + .collect(Collectors.joining(",")); return this.getBlockType().getId() + "[" + properties + "]"; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java index e05ba9e60..7ee097d94 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/Snapshot.java @@ -35,6 +35,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.time.ZonedDateTime; +import java.util.Locale; import java.util.zip.ZipFile; /** @@ -83,7 +84,8 @@ public class Snapshot implements Comparable { * @throws DataException */ private ChunkStore internalGetChunkStore() throws IOException, DataException { - if (file.getName().toLowerCase().endsWith(".zip")) { + String lowerCaseFileName = file.getName().toLowerCase(Locale.ROOT); + if (lowerCaseFileName.endsWith(".zip")) { try { ChunkStore chunkStore = new TrueZipMcRegionChunkStore(file); @@ -101,9 +103,9 @@ public class Snapshot implements Comparable { return chunkStore; } - } else if (file.getName().toLowerCase().endsWith(".tar.bz2") - || file.getName().toLowerCase().endsWith(".tar.gz") - || file.getName().toLowerCase().endsWith(".tar")) { + } else if (lowerCaseFileName.endsWith(".tar.bz2") + || lowerCaseFileName.endsWith(".tar.gz") + || lowerCaseFileName.endsWith(".tar")) { try { ChunkStore chunkStore = new TrueZipMcRegionChunkStore(file); @@ -133,14 +135,15 @@ public class Snapshot implements Comparable { */ public boolean containsWorld(String worldname) { try { - if (file.getName().toLowerCase().endsWith(".zip")) { + String lowerCaseFileName = file.getName().toLowerCase(Locale.ROOT); + if (lowerCaseFileName.endsWith(".zip")) { try (ZipFile entry = new ZipFile(file)) { return (entry.getEntry(worldname) != null || entry.getEntry(worldname + "/level.dat") != null); } - } else if (file.getName().toLowerCase().endsWith(".tar.bz2") - || file.getName().toLowerCase().endsWith(".tar.gz") - || file.getName().toLowerCase().endsWith(".tar")) { + } else if (lowerCaseFileName.endsWith(".tar.bz2") + || lowerCaseFileName.endsWith(".tar.gz") + || lowerCaseFileName.endsWith(".tar")) { try { de.schlichtherle.util.zip.ZipFile entry = new de.schlichtherle.util.zip.ZipFile(file); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java index 1838c2747..e6fe6aec7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/SnapshotRepository.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; +import java.util.Locale; /** * A repository contains zero or more snapshots. @@ -208,11 +209,17 @@ public class SnapshotRepository { return false; } - return (file.isDirectory() && (new File(file, "level.dat")).exists()) - || (file.isFile() && (file.getName().toLowerCase().endsWith(".zip") - || file.getName().toLowerCase().endsWith(".tar.bz2") - || file.getName().toLowerCase().endsWith(".tar.gz") - || file.getName().toLowerCase().endsWith(".tar"))); + if (file.isDirectory() && new File(file, "level.dat").exists()) { + return true; + } + if (file.isFile()) { + String lowerCaseFileName = file.getName().toLowerCase(Locale.ROOT); + return lowerCaseFileName.endsWith(".zip") + || lowerCaseFileName.endsWith(".tar.bz2") + || lowerCaseFileName.endsWith(".tar.gz") + || lowerCaseFileName.endsWith(".tar"); + } + return false; } /** From b419446109b8d832da65ccfb5dedcf8a554f27de Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 1 May 2019 00:12:20 -0700 Subject: [PATCH 103/366] Add checkstyle regexp to validate case methods --- config/checkstyle/checkstyle.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 0fe76dff3..89177a84c 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -57,6 +57,12 @@ + + + + + + From 5781b4cd760502222a2f352009456fdd63a38da8 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 1 May 2019 15:46:54 -0700 Subject: [PATCH 104/366] Update Piston version --- worldedit-libs/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 00d33be30..17ed2d74c 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -89,7 +89,7 @@ configure(subprojects + project("core:ap")) { } project("core") { - def pistonVersion = '0.1.0' + def pistonVersion = '0.1.1' dependencies { shade 'net.kyori:text-api:2.0.0' From 5e81dd1c4ccb5853a34d89b2b030b2745b8b37cc Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 1 May 2019 19:59:02 -0400 Subject: [PATCH 105/366] Make registries Keyed. --- .../command/argument/RegistryConverter.java | 11 ++++--- .../sk89q/worldedit/registry/Category.java | 2 +- .../com/sk89q/worldedit/registry/Keyed.java | 32 +++++++++++++++++++ .../registry/NamespacedRegistry.java | 7 ++-- .../sk89q/worldedit/registry/Registry.java | 5 +-- .../formatting/component/PaginationBox.java | 6 ++++ .../worldedit/world/biome/BiomeType.java | 4 ++- .../worldedit/world/block/BlockCategory.java | 3 +- .../worldedit/world/block/BlockType.java | 4 ++- .../worldedit/world/entity/EntityType.java | 4 ++- .../worldedit/world/fluid/FluidCategory.java | 3 +- .../worldedit/world/fluid/FluidType.java | 4 ++- .../worldedit/world/gamemode/GameMode.java | 4 ++- .../worldedit/world/gamemode/GameModes.java | 4 +-- .../worldedit/world/item/ItemCategory.java | 3 +- .../sk89q/worldedit/world/item/ItemType.java | 4 ++- .../world/registry/CategoryRegistry.java | 3 +- .../worldedit/world/weather/WeatherType.java | 4 ++- 18 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java index 7bafb86e9..a37c5b174 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.command.argument; import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.Registry; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -46,7 +47,7 @@ import java.util.List; import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; -public class RegistryConverter implements ArgumentConverter { +public final class RegistryConverter implements ArgumentConverter { @SuppressWarnings("unchecked") public static void register(CommandManager commandManager) { @@ -62,18 +63,18 @@ public class RegistryConverter implements ArgumentConverter { GameMode.class, WeatherType.class ).stream() - .map(c -> (Class) c) + .map(c -> (Class) c) .forEach(registryType -> commandManager.registerConverter(Key.of(registryType), from(registryType)) ); } @SuppressWarnings("unchecked") - private static RegistryConverter from(Class registryType) { + private static RegistryConverter from(Class registryType) { try { Field registryField = registryType.getDeclaredField("REGISTRY"); Registry registry = (Registry) registryField.get(null); - return new RegistryConverter<>(registryType, registry); + return new RegistryConverter<>(registry); } catch (NoSuchFieldException e) { throw new IllegalArgumentException("Not a registry-backed type: " + registryType.getName()); } catch (IllegalAccessException e) { @@ -84,7 +85,7 @@ public class RegistryConverter implements ArgumentConverter { private final Registry registry; private final TextComponent choices; - private RegistryConverter(Class clazz, Registry registry) { + private RegistryConverter(Registry registry) { this.registry = registry; this.choices = TextComponent.of("any " + registry.getName()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java index 0f7f256a8..e3c0941d8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Category.java @@ -22,7 +22,7 @@ package com.sk89q.worldedit.registry; import java.util.HashSet; import java.util.Set; -public abstract class Category { +public abstract class Category { private final Set set = new HashSet<>(); protected final String id; private boolean empty = true; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java new file mode 100644 index 000000000..5351ed36b --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java @@ -0,0 +1,32 @@ +/* + * 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.registry; + +/** + * Represents an objects that can be added to a registry and referenced by an id which is unique within its registry. + */ +public interface Keyed { + /** + * The id of this object in the registry. Must be unique, and lowercase. Certain registries (e.g Namespaced ones) may have additional restrictions. + * @return an id + */ + String getId(); +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java index d3b151f6e..4519bbc88 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java @@ -24,7 +24,7 @@ import static java.util.Objects.requireNonNull; import javax.annotation.Nullable; -public final class NamespacedRegistry extends Registry { +public final class NamespacedRegistry extends Registry { private static final String MINECRAFT_NAMESPACE = "minecraft"; private final String defaultNamespace; @@ -37,10 +37,13 @@ public final class NamespacedRegistry extends Registry { this.defaultNamespace = defaultNamespace; } - public @Nullable V get(final String key) { + @Nullable + @Override + public V get(final String key) { return super.get(this.orDefaultNamespace(key)); } + @Override public V register(final String key, final V value) { requireNonNull(key, "key"); checkState(key.indexOf(':') > -1, "key is not namespaced"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java index 8d8bf46c4..fcd673eb4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Registry.java @@ -32,7 +32,7 @@ import java.util.Set; import javax.annotation.Nullable; -public class Registry implements Iterable { +public class Registry implements Iterable { private final Map map = new HashMap<>(); private final String name; @@ -44,7 +44,8 @@ public class Registry implements Iterable { return name; } - public @Nullable V get(final String key) { + @Nullable + public V get(final String key) { checkState(key.equals(key.toLowerCase(Locale.ROOT)), "key must be lowercase"); return this.map.get(key); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java index bba74a4db..6d33d1a5f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java @@ -34,6 +34,7 @@ public abstract class PaginationBox extends MessageBox { private String pageCommand; private int componentsPerPage = IDEAL_ROWS_FOR_PLAYER; + private int currentPage = -1; /** * Creates a Paginated component @@ -57,6 +58,10 @@ public abstract class PaginationBox extends MessageBox { this.componentsPerPage = 20; } + protected final int getCurrentPage() { + return currentPage; + } + /** * Creates a Paginated component * @@ -80,6 +85,7 @@ public abstract class PaginationBox extends MessageBox { if (page < 1 || page > pageCount) { throw new InvalidComponentException("Invalid page number."); } + currentPage = page; final int lastComp = Math.min(page * componentsPerPage, getComponentsSize()); for (int i = (page - 1) * componentsPerPage; i < lastComp; i++) { getContents().append(getComponent(i)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java index 7dc155253..fe9203c70 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java @@ -19,12 +19,13 @@ package com.sk89q.worldedit.world.biome; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; /** * All the types of biomes in the game. */ -public class BiomeType { +public class BiomeType implements Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("biome type"); @@ -39,6 +40,7 @@ public class BiomeType { * * @return The id */ + @Override public String getId() { return this.id; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategory.java index 161b1c304..19a1cbc82 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategory.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.world.block; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; import java.util.Set; @@ -30,7 +31,7 @@ import java.util.Set; * A category of blocks. This is due to the splitting up of * blocks such as wool into separate ids. */ -public class BlockCategory extends Category { +public class BlockCategory extends Category implements Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("block tag"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java index 633f00a3f..e86ee7e83 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java @@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.item.ItemType; @@ -41,7 +42,7 @@ import java.util.function.Supplier; import javax.annotation.Nullable; -public class BlockType { +public class BlockType implements Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("block type"); @@ -91,6 +92,7 @@ public class BlockType { * * @return The id */ + @Override public String getId() { return this.id; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java index 71779e953..245bfb2e5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityType.java @@ -19,9 +19,10 @@ package com.sk89q.worldedit.world.entity; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; -public class EntityType { +public class EntityType implements Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("entity type"); @@ -35,6 +36,7 @@ public class EntityType { this.id = id; } + @Override public String getId() { return this.id; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategory.java index 52685cb56..721c22aad 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategory.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.world.fluid; import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; import java.util.Collections; @@ -29,7 +30,7 @@ import java.util.Set; * A category of fluids. This is due to the splitting up of * blocks such as wool into separate ids. */ -public class FluidCategory extends Category { +public class FluidCategory extends Category implements Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("fluid tag"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java index 5b94015e1..b5e137ee6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java @@ -19,13 +19,14 @@ package com.sk89q.worldedit.world.fluid; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; /** * Minecraft now has a 'fluid' system. This is a * stub class to represent what it may be in the future. */ -public class FluidType { +public class FluidType implements Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("fluid type"); @@ -40,6 +41,7 @@ public class FluidType { * * @return The id */ + @Override public String getId() { return this.id; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java index 9cfd4b111..b64d960de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameMode.java @@ -19,9 +19,10 @@ package com.sk89q.worldedit.world.gamemode; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.Registry; -public class GameMode { +public class GameMode implements Keyed { public static final Registry REGISTRY = new Registry<>("game mode"); @@ -31,6 +32,7 @@ public class GameMode { this.id = id; } + @Override public String getId() { return this.id; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java index ab5b9fc69..0e5673221 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java @@ -23,7 +23,6 @@ import javax.annotation.Nullable; public class GameModes { - public static final GameMode NOT_SET = register(""); public static final GameMode SURVIVAL = register("survival"); public static final GameMode CREATIVE = register("creative"); public static final GameMode ADVENTURE = register("adventure"); @@ -40,7 +39,8 @@ public class GameModes { return GameMode.REGISTRY.register(gameMode.getId(), gameMode); } - public static @Nullable GameMode get(final String id) { + @Nullable + public static GameMode get(final String id) { return GameMode.REGISTRY.get(id); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategory.java index c5efdb4b9..8858dc9f9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategory.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; import java.util.Set; @@ -31,7 +32,7 @@ import java.util.Set; * A category of items. This is due to the splitting up of * items such as wool into separate ids. */ -public class ItemCategory extends Category { +public class ItemCategory extends Category implements Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("item tag"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java index ab151729f..6654d5dec 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java @@ -21,13 +21,14 @@ package com.sk89q.worldedit.world.item; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import javax.annotation.Nullable; -public class ItemType { +public class ItemType implements Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("item type"); @@ -41,6 +42,7 @@ public class ItemType { this.id = id; } + @Override public String getId() { return this.id; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java index 496893821..0de14a17c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java @@ -20,13 +20,14 @@ package com.sk89q.worldedit.world.registry; import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.registry.Keyed; import java.util.Set; /** * A registry of categories. Minecraft internally calls these 'Tags'. */ -public interface CategoryRegistry { +public interface CategoryRegistry { /** * Gets a set of values with a given category. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java index c44392df0..43f689d8c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherType.java @@ -19,9 +19,10 @@ package com.sk89q.worldedit.world.weather; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.Registry; -public class WeatherType { +public class WeatherType implements Keyed { public static final Registry REGISTRY = new Registry<>("weather type"); @@ -31,6 +32,7 @@ public class WeatherType { this.id = id; } + @Override public String getId() { return this.id; } From 57c161a602f6537c9b32ed36d655bb10b91aae7d Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 2 May 2019 00:08:19 -0400 Subject: [PATCH 106/366] Actually initialize GameModes and WeatherTypes. --- .../worldedit/bukkit/WorldEditPlugin.java | 5 ++++ .../worldedit/world/block/BlockTypes.java | 3 ++- .../worldedit/world/gamemode/GameModes.java | 2 +- .../worldedit/world/weather/WeatherTypes.java | 26 ++++++++++--------- 4 files changed, 22 insertions(+), 14 deletions(-) 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 f53223a53..ff0b03a21 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 @@ -44,8 +44,10 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.FuzzyBlockState; import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemCategory; import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.weather.WeatherTypes; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -173,6 +175,9 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { EntityType.REGISTRY.register("minecraft:" + lowerCaseMcId, new EntityType("minecraft:" + lowerCaseMcId)); } } + // ... :| + GameModes.get(""); + WeatherTypes.get(""); } private void setupTags() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java index 2d9f1a4ba..1b8b44bcc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java @@ -628,7 +628,8 @@ public final class BlockTypes { private BlockTypes() { } - public static @Nullable BlockType get(final String id) { + @Nullable + public static BlockType get(final String id) { return BlockType.REGISTRY.get(id); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java index 0e5673221..f3a0fc4b2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/gamemode/GameModes.java @@ -21,7 +21,7 @@ package com.sk89q.worldedit.world.gamemode; import javax.annotation.Nullable; -public class GameModes { +public final class GameModes { public static final GameMode SURVIVAL = register("survival"); public static final GameMode CREATIVE = register("creative"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java index d7450610d..dd0f07e27 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/weather/WeatherTypes.java @@ -21,23 +21,25 @@ package com.sk89q.worldedit.world.weather; import javax.annotation.Nullable; -public class WeatherTypes { +public final class WeatherTypes { - static { - // This isn't really a proper registry - so inject these before they're obtained. - WeatherType.REGISTRY.register("clear", new WeatherType("clear")); - WeatherType.REGISTRY.register("rain", new WeatherType("rain")); - WeatherType.REGISTRY.register("thunder_storm", new WeatherType("thunder_storm")); - } - - @Nullable public static final WeatherType CLEAR = get("clear"); - @Nullable public static final WeatherType RAIN = get("rain"); - @Nullable public static final WeatherType THUNDER_STORM = get("thunder_storm"); + public static final WeatherType CLEAR = register("clear"); + public static final WeatherType RAIN = register("rain"); + public static final WeatherType THUNDER_STORM = register("thunder_storm"); private WeatherTypes() { } - public static @Nullable WeatherType get(final String id) { + private static WeatherType register(String id) { + return register(new WeatherType(id)); + } + + public static WeatherType register(WeatherType weather) { + return WeatherType.REGISTRY.register(weather.getId(), weather); + } + + @Nullable + public static WeatherType get(final String id) { return WeatherType.REGISTRY.get(id); } } From 018b6bead8eafd57ce6cfde2d12db8f0fea58107 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 2 May 2019 18:15:04 -0400 Subject: [PATCH 107/366] Tweak removeabove/removebelow commands. Fix misplaced negative. Layer 0 will always be the current layer, plus layers above/below. No longer adds 1 arbitrarily to height. --- .../java/com/sk89q/worldedit/command/UtilityCommands.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 0e18dbcbd..af59e5adc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -197,10 +197,9 @@ public class UtilityCommands { size = Math.max(1, size); we.checkMaxRadius(size); World world = player.getWorld(); - height = height != null ? Math.min((world.getMaxY() + 1), height + 2) : (world.getMaxY() + 1); + height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1); - int affected = editSession.removeAbove( - session.getPlacementPosition(player), size, height); + int affected = editSession.removeAbove(session.getPlacementPosition(player), size, height); player.print(affected + " block(s) have been removed."); return affected; } @@ -220,7 +219,7 @@ public class UtilityCommands { size = Math.max(1, size); we.checkMaxRadius(size); World world = player.getWorld(); - height = height != null ? Math.min((-world.getMaxY() + 1), height + 2) : (world.getMaxY() + 1); + height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1); int affected = editSession.removeBelow(session.getPlacementPosition(player), size, height); player.print(affected + " block(s) have been removed."); From f279907616cb958f40cd0f6112580585cef782b5 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 4 May 2019 17:06:19 -0400 Subject: [PATCH 108/366] Create CommandManagerService directly instead of service loading it. --- .../worldedit/extension/platform/PlatformCommandManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 0e6420c4d..f5359b478 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -109,6 +109,7 @@ import org.enginehub.piston.exception.CommandExecutionException; import org.enginehub.piston.exception.ConditionFailedException; import org.enginehub.piston.exception.UsageException; import org.enginehub.piston.gen.CommandRegistration; +import org.enginehub.piston.impl.CommandManagerServiceImpl; import org.enginehub.piston.inject.InjectedValueStore; import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.MapBackedValueStore; @@ -164,8 +165,7 @@ public final class PlatformCommandManager { this.worldEdit = worldEdit; this.platformManager = platformManager; this.exceptionConverter = new WorldEditExceptionConverter(worldEdit); - this.commandManager = DefaultCommandManagerService.getInstance() - .newCommandManager(); + this.commandManager = new CommandManagerServiceImpl().newCommandManager(); this.globalInjectedValues = MapBackedValueStore.create(); this.registration = new CommandRegistrationHandler( ImmutableList.of( From ac66ab66c3f89af664cfe6276462f9e7ce3d1659 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 4 May 2019 21:00:00 -0400 Subject: [PATCH 109/366] Remove mentions of setupDecompWorkspace in COMPILING.md. This task is no longer needed or used. Fixes WORLDEDIT-3886. --- COMPILING.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/COMPILING.md b/COMPILING.md index d3e5bac5c..219ce0bfc 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -16,14 +16,12 @@ The build process uses Gradle, which you do *not* need to download. WorldEdit is ### On Windows 1. Shift + right click the folder with WorldEdit's files and click "Open command prompt". -2. `gradlew clean setupDecompWorkspace` -3. `gradlew build` +2. `gradlew build` ### On Linux, BSD, or Mac OS X 1. In your terminal, navigate to the folder with WorldEdit's files (`cd /folder/of/worldedit/files`) -2. `./gradlew clean setupDecompWorkspace` -3. `./gradlew build` +2. `./gradlew build` ## Then you will find... @@ -38,8 +36,8 @@ If you want to use WorldEdit, use the `-dist` version. (The -dist version includes WorldEdit + necessary libraries.) -### Note regarding `setupDecompWorkspace` -`setupDecompWorkspace` requires more memory than is usually given to Gradle by default. +### Note regarding Forge builds +The build system used for forge (ForgeGradle) requires more memory than is usually given to Gradle by default. If it fails, you should put `org.gradle.jvmargs=-Xmx3G` in `gradle.properties`. Please don't commit this change! @@ -47,4 +45,3 @@ Please don't commit this change! * `gradlew idea` will generate an [IntelliJ IDEA](http://www.jetbrains.com/idea/) module for each folder. * `gradlew eclipse` will generate an [Eclipse](https://www.eclipse.org/downloads/) project for each folder. -* Use `setupCIWorkspace` instead of `setupDecompWorkspace` if you are doing this on a CI server. From bc8e477b1cafb0ec8daf4ea16462b09a13c88412 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 4 May 2019 22:48:49 -0400 Subject: [PATCH 110/366] Fix error message with invalid //expand args. --- .../sk89q/worldedit/command/argument/ExpandAmountConverter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java index 4d431ebca..b54311bee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java @@ -49,7 +49,7 @@ public class ExpandAmountConverter implements ArgumentConverter { @Override public Component describeAcceptableArguments() { - return TextComponent.of("`vert` or " + integerConverter.describeAcceptableArguments()); + return TextComponent.of("`vert` or ").append(integerConverter.describeAcceptableArguments()); } @Override From ceff17c4f7c7c87df963ae0c33cd929ada628323 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 5 May 2019 14:25:43 -0400 Subject: [PATCH 111/366] Misc fixes. Closes a few old youtrack issues which I don't remember because I had like 30 tabs open, and a few other issues which I found while testing some of those. --- .../com/sk89q/wepif/ConfigurationPermissionsResolver.java | 6 +++--- .../java/com/sk89q/worldedit/function/GroundFunction.java | 2 +- .../command/exception/WorldEditExceptionConverter.java | 2 +- .../java/com/sk89q/worldedit/session/SessionManager.java | 1 + .../util/formatting/component/SchematicPaginationBox.java | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java b/worldedit-bukkit/src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java index bdf1ba0ba..763e4f88d 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/wepif/ConfigurationPermissionsResolver.java @@ -59,7 +59,7 @@ public class ConfigurationPermissionsResolver implements PermissionsResolver { Map> userGroupPermissions = new HashMap<>(); - List groupKeys = config.getStringList("permissions.groups", null); + List groupKeys = config.getKeys("permissions.groups"); if (groupKeys != null) { for (String key : groupKeys) { @@ -77,7 +77,7 @@ public class ConfigurationPermissionsResolver implements PermissionsResolver { } } - List userKeys = config.getStringList("permissions.users", null); + List userKeys = config.getKeys("permissions.users"); if (userKeys != null) { for (String key : userKeys) { @@ -150,7 +150,7 @@ public class ConfigurationPermissionsResolver implements PermissionsResolver { return new String[0]; } - return groups.toArray(new String[groups.size()]); + return groups.toArray(new String[0]); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/GroundFunction.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/GroundFunction.java index d3162ff13..5e4c7c545 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/GroundFunction.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/GroundFunction.java @@ -85,9 +85,9 @@ public class GroundFunction implements LayerFunction { if (depth == 0) { if (function.apply(position)) { affected++; + return true; } } - return false; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java index a0100fc4c..b200e11b3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java @@ -61,7 +61,7 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { } private CommandException newCommandException(String message, Throwable cause) { - return new CommandException(TextComponent.of(message), cause, ImmutableList.of()); + return new CommandException(TextComponent.of(String.valueOf(message)), cause, ImmutableList.of()); } @ExceptionMatch diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index e393fe115..ba2468bd0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -261,6 +261,7 @@ public class SessionManager { */ public synchronized void unload() { clear(); + timer.cancel(); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java index eb9598a49..9617b31dd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java @@ -46,7 +46,7 @@ public class SchematicPaginationBox extends PaginationBox { @Override public Component getComponent(int number) { - checkArgument(number < files.length - 1 && number >= 0); + checkArgument(number < files.length && number >= 0); File file = files[number]; Multimap exts = ClipboardFormats.getFileExtensionMap(); String format = exts.get(Files.getFileExtension(file.getName())) From acc0e7d09c7c59915f8e58237d65d2f2bbff219d Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 4 May 2019 02:20:02 -0700 Subject: [PATCH 112/366] Fix logging on Bukkit, align adapter versions --- worldedit-bukkit/build.gradle | 5 +++-- worldedit-forge/build.gradle | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 7c5ded7b9..b771a1aa7 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -20,7 +20,7 @@ dependencies { compile 'com.sk89q:dummypermscompat:1.10' compile 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz compile "io.papermc:paperlib:1.0.1" - compile 'org.slf4j:slf4j-jdk14:1.7.26' + compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' compile 'org.bstats:bstats-bukkit:1.4' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } @@ -46,9 +46,10 @@ jar { shadowJar { dependencies { relocate "org.slf4j", "com.sk89q.worldedit.slf4j" + relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge" include(dependency(':worldedit-core')) include(dependency('org.slf4j:slf4j-api')) - include(dependency("org.slf4j:slf4j-jdk14")) + include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) relocate ("org.bstats", "com.sk89q.worldedit.bukkit.bstats") { include(dependency("org.bstats:bstats-bukkit:1.4")) } diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 62ee93b26..2b0b08b52 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -24,7 +24,7 @@ configurations.all { Configuration it -> dependencies { compile project(':worldedit-core') - compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.2' + compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}" From 4355f8cbf7f380708208750cdffb79e31e3e6027 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 4 May 2019 02:20:20 -0700 Subject: [PATCH 113/366] Update Piston for suggestions, add hacky-pseudo-suggestions --- .../platform/PlatformCommandManager.java | 69 +++++++++++-------- worldedit-libs/build.gradle | 2 +- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index f5359b478..e1d293303 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extension.platform; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.common.reflect.TypeToken; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.IncompleteRegionException; @@ -85,13 +86,13 @@ import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.internal.annotation.Selection; +import com.sk89q.worldedit.internal.command.CommandArgParser; import com.sk89q.worldedit.internal.command.CommandLoggingHandler; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; import com.sk89q.worldedit.internal.command.exception.WorldEditExceptionConverter; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; -import com.sk89q.worldedit.internal.command.CommandArgParser; -import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; -import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; @@ -116,6 +117,7 @@ import org.enginehub.piston.inject.MapBackedValueStore; import org.enginehub.piston.inject.MemoizingValueAccess; import org.enginehub.piston.inject.MergedValueAccess; import org.enginehub.piston.part.SubCommandPart; +import org.enginehub.piston.suggestion.Suggestion; import org.enginehub.piston.util.HelpGenerator; import org.enginehub.piston.util.ValueProvider; import org.slf4j.Logger; @@ -123,6 +125,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Optional; @@ -441,7 +444,9 @@ public final class PlatformCommandManager { } private String[] parseArgs(String input) { - return new CommandArgParser(input).parseArgs().toArray(String[]::new); + return commandDetection(new CommandArgParser(input.substring(1)) + .parseArgs() + .toArray(String[]::new)); } @Subscribe @@ -449,7 +454,7 @@ public final class PlatformCommandManager { Request.reset(); Actor actor = platformManager.createProxyActor(event.getActor()); - String[] split = commandDetection(parseArgs(event.getArguments().substring(1))); + String[] split = parseArgs(event.getArguments()); // No command found! if (!commandManager.containsCommand(split[0])) { @@ -466,26 +471,7 @@ public final class PlatformCommandManager { } LocalConfiguration config = worldEdit.getConfiguration(); - InjectedValueStore store = MapBackedValueStore.create(); - store.injectValue(Key.of(Actor.class), ValueProvider.constant(actor)); - if (actor instanceof Player) { - store.injectValue(Key.of(Player.class), ValueProvider.constant((Player) actor)); - } else { - store.injectValue(Key.of(Player.class), context -> { - throw new CommandException(TextComponent.of("This command must be used with a player."), ImmutableList.of()); - }); - } - store.injectValue(Key.of(Arguments.class), ValueProvider.constant(event::getArguments)); - store.injectValue(Key.of(LocalSession.class), - context -> { - LocalSession localSession = worldEdit.getSessionManager().get(actor); - localSession.tellVersion(actor); - return Optional.of(localSession); - }); - - MemoizingValueAccess context = MemoizingValueAccess.wrap( - MergedValueAccess.of(store, globalInjectedValues) - ); + MemoizingValueAccess context = initializeInjectedValues(event::getArguments, actor); long start = System.currentTimeMillis(); @@ -563,6 +549,29 @@ public final class PlatformCommandManager { event.setCancelled(true); } + private MemoizingValueAccess initializeInjectedValues(Arguments arguments, Actor actor) { + InjectedValueStore store = MapBackedValueStore.create(); + store.injectValue(Key.of(Actor.class), ValueProvider.constant(actor)); + if (actor instanceof Player) { + store.injectValue(Key.of(Player.class), ValueProvider.constant((Player) actor)); + } else { + store.injectValue(Key.of(Player.class), context -> { + throw new CommandException(TextComponent.of("This command must be used with a player."), ImmutableList.of()); + }); + } + store.injectValue(Key.of(Arguments.class), ValueProvider.constant(arguments)); + store.injectValue(Key.of(LocalSession.class), + context -> { + LocalSession localSession = worldEdit.getSessionManager().get(actor); + localSession.tellVersion(actor); + return Optional.of(localSession); + }); + + return MemoizingValueAccess.wrap( + MergedValueAccess.of(store, globalInjectedValues) + ); + } + private void handleUnknownException(Actor actor, Throwable t) { actor.printError("Please report this error: [See console]"); actor.printRaw(t.getClass().getName() + ": " + t.getMessage()); @@ -572,9 +581,13 @@ public final class PlatformCommandManager { @Subscribe public void handleCommandSuggestion(CommandSuggestionEvent event) { try { - globalInjectedValues.injectValue(Key.of(Actor.class), ValueProvider.constant(event.getActor())); - globalInjectedValues.injectValue(Key.of(Arguments.class), ValueProvider.constant(event::getArguments)); - // TODO suggestions + String[] split = parseArgs(event.getArguments()); + MemoizingValueAccess access = initializeInjectedValues(event::getArguments, event.getActor()); + ImmutableSet suggestions = commandManager.getSuggestions(access, Arrays.asList(split)); + + log.debug("For input: {}", event.getArguments()); + log.debug("I would suggest this: {}", suggestions); + // TODO send back suggestions } catch (CommandException e) { event.getActor().printError(e.getMessage()); } diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 17ed2d74c..ec33995f5 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -89,7 +89,7 @@ configure(subprojects + project("core:ap")) { } project("core") { - def pistonVersion = '0.1.1' + def pistonVersion = '0.1.2' dependencies { shade 'net.kyori:text-api:2.0.0' From 1c54a04fd10063912be19fb8b4aa9ab264908daa Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 5 May 2019 01:37:11 -0700 Subject: [PATCH 114/366] Update Text to 3 --- .../CommaSeparatedValuesConverter.java | 4 +-- .../formatting/component/CommandListBox.java | 8 +++--- .../util/formatting/component/MessageBox.java | 4 +-- .../formatting/component/PaginationBox.java | 8 +++--- .../component/SchematicPaginationBox.java | 8 +++--- .../component/TextComponentProducer.java | 2 +- worldedit-libs/build.gradle | 25 ++++++++++++++----- 7 files changed, 36 insertions(+), 23 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java index 7479ff375..e02747c3e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/CommaSeparatedValuesConverter.java @@ -32,7 +32,7 @@ import org.enginehub.piston.inject.InjectedValueAccess; import java.util.List; import static com.google.common.base.Preconditions.checkArgument; -import static com.sk89q.worldedit.util.formatting.text.Component.space; +import static com.sk89q.worldedit.util.formatting.text.TextComponent.space; public class CommaSeparatedValuesConverter implements ArgumentConverter { @@ -61,7 +61,7 @@ public class CommaSeparatedValuesConverter implements ArgumentConverter { TextComponent.Builder result = TextComponent.builder(""); if (maximum > -1) { result.append(TextComponent.of("up to ")) - .append(Component.of(maximum)) + .append(TextComponent.of(maximum)) .append(space()); } result.append(TextComponent.of("comma separated values of: ")) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java index e1b889059..fd579c6fb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -87,16 +87,16 @@ public class CommandListBox extends PaginationBox { TextComponentProducer line = new TextComponentProducer(); if (!hideHelp) { line.append(SubtleFormat.wrap("? ") - .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "//help " + insertion)) - .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help")))); + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//help " + insertion)) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help")))); } TextComponent command = TextComponent.of(alias, TextColor.GOLD); if (insertion == null) { line.append(command); } else { line.append(command - .clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, insertion)) - .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select")))); + .clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, insertion)) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to select")))); } return line.append(TextComponent.of(": ")).append(description).create(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java index 1497ddbaa..e5fceb008 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/MessageBox.java @@ -55,11 +55,11 @@ public class MessageBox extends TextComponentProducer { if (side > 1) { line.append(createBorder(side - 1)); } - line.append(Component.space()); + line.append(TextComponent.space()); } line.append(text); if (side > 0) { - line.append(Component.space()); + line.append(TextComponent.space()); if (side > 1) { line.append(createBorder(side - 1)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java index 6d33d1a5f..9308d326c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java @@ -105,15 +105,15 @@ public abstract class PaginationBox extends MessageBox { TextComponentProducer navProducer = new TextComponentProducer(); if (page > 1) { TextComponent prevComponent = TextComponent.of("<<< ", TextColor.GOLD) - .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page - 1)))) - .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate"))); + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page - 1)))) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate"))); navProducer.append(prevComponent); } navProducer.append(pageNumberComponent); if (page < pageCount) { TextComponent nextComponent = TextComponent.of(" >>>", TextColor.GOLD) - .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page + 1)))) - .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate"))); + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, pageCommand.replace("%page%", String.valueOf(page + 1)))) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to navigate"))); navProducer.append(nextComponent); } getContents().append(centerAndBorder(navProducer.create())); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java index 9617b31dd..ae052d137 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java @@ -59,12 +59,12 @@ public class SchematicPaginationBox extends PaginationBox { .content("") .append(TextComponent.of("[L]") .color(TextColor.GOLD) - .clickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem load " + path)) - .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load")))) - .append(Component.space()) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load " + path)) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load")))) + .append(TextComponent.space()) .append(TextComponent.of(path) .color(TextColor.DARK_GREEN) - .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format)))) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format)))) .build(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java index fed34ea23..b22b44f08 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/TextComponentProducer.java @@ -58,7 +58,7 @@ public class TextComponentProducer { * @return The producer, for chaining */ public TextComponentProducer newline() { - getBuilder().append(Component.newline()); + getBuilder().append(TextComponent.newline()); return this; } diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index ec33995f5..c6a53795e 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -88,13 +88,14 @@ configure(subprojects + project("core:ap")) { build.dependsOn(jar, sourcesJar) } +def textVersion = "3.0.0" project("core") { - def pistonVersion = '0.1.2' + def pistonVersion = '0.2.0' dependencies { - shade 'net.kyori:text-api:2.0.0' - shade 'net.kyori:text-serializer-gson:2.0.0' - shade 'net.kyori:text-serializer-legacy:2.0.0' + shade "net.kyori:text-api:$textVersion" + shade "net.kyori:text-serializer-gson:$textVersion" + shade "net.kyori:text-serializer-legacy:$textVersion" shade('com.sk89q:jchronic:0.2.4a') { exclude(group: "junit", module: "junit") } @@ -113,13 +114,25 @@ project("core") { } } project("bukkit") { + repositories { + maven { + name = "SpigotMC" + url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" + } + } dependencies { - shade 'net.kyori:text-adapter-bukkit:2.0.0-SNAPSHOT' + shade "net.kyori:text-adapter-bukkit:$textVersion" } } project("sponge") { + repositories { + maven { + name = "Sponge" + url = "https://repo.spongepowered.org/maven" + } + } dependencies { - shade 'net.kyori:text-adapter-spongeapi:2.0.0-SNAPSHOT' + shade "net.kyori:text-adapter-spongeapi:$textVersion" } } From 8a3e6a12b9a2dc75bf9f381d26b57293d443d1de Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 5 May 2019 22:06:20 -0700 Subject: [PATCH 115/366] Implement suggestions for Bukkit + Sponge --- .../worldedit/bukkit/WorldEditListener.java | 30 ----- .../worldedit/bukkit/WorldEditPlugin.java | 6 +- .../sk89q/worldedit/LocalConfiguration.java | 1 - .../platform/CommandSuggestionEvent.java | 16 ++- .../platform/PlatformCommandManager.java | 63 +++++----- .../internal/command/CommandArgParser.java | 108 ++++++++++-------- .../internal/command/CommandUtil.java | 44 +++++++ .../worldedit/internal/util/Substring.java | 97 ++++++++++++++++ .../util/PropertiesConfiguration.java | 1 - .../worldedit/util/YAMLConfiguration.java | 2 - .../command/CommandArgParserTest.java | 51 +++++++++ worldedit-forge/build.gradle | 2 +- worldedit-libs/build.gradle | 2 +- .../worldedit/sponge/SpongePlatform.java | 3 +- .../config/ConfigurateConfiguration.java | 2 - 15 files changed, 295 insertions(+), 133 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/Substring.java create mode 100644 worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java index 7eea4312b..15361fc10 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java @@ -80,36 +80,6 @@ public class WorldEditListener implements Listener { WorldEdit.getInstance().getSessionManager().get(plugin.wrapPlayer(event.getPlayer())); } - /** - * Called when a player attempts to use a command - * - * @param event Relevant event details - */ - @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - String[] split = event.getMessage().split(" "); - - if (split.length > 0) { - split[0] = split[0].substring(1); - split = plugin.getWorldEdit().getPlatformManager().getPlatformCommandManager().commandDetection(split); - } - - final String newMessage = "/" + StringUtil.joinString(split, " "); - - if (!newMessage.equals(event.getMessage())) { - event.setMessage(newMessage); - plugin.getServer().getPluginManager().callEvent(event); - - if (!event.isCancelled()) { - if (!event.getMessage().isEmpty()) { - plugin.getServer().dispatchCommand(event.getPlayer(), event.getMessage().substring(1)); - } - - event.setCancelled(true); - } - } - } - @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onPlayerCommand(PlayerCommandSendEvent event) { InjectedValueStore store = MapBackedValueStore.create(); 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 ff0b03a21..11fc7de09 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 @@ -37,6 +37,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.internal.command.CommandUtil; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockCategory; @@ -313,9 +314,10 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { System.arraycopy(args, 0, split, 1, args.length); split[0] = "/" + cmd.getName(); - CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), Joiner.on(" ").join(split)); + String arguments = Joiner.on(" ").join(split); + CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), arguments); getWorldEdit().getEventBus().post(event); - return event.getSuggestions(); + return CommandUtil.fixSuggestions(arguments, event.getSuggestions()); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index 51ace98a8..08594fcfb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -58,7 +58,6 @@ public abstract class LocalConfiguration { public String wandItem = "minecraft:wooden_axe"; public boolean superPickaxeDrop = true; public boolean superPickaxeManyDrop = true; - public boolean noDoubleSlash = false; public boolean useInventory = false; public boolean useInventoryOverride = false; public boolean useInventoryCreativeOverride = false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java index 75483745e..709bcc49c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/event/platform/CommandSuggestionEvent.java @@ -19,14 +19,15 @@ package com.sk89q.worldedit.event.platform; -import static com.google.common.base.Preconditions.checkNotNull; - import com.sk89q.worldedit.event.Event; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.util.Substring; import java.util.Collections; import java.util.List; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Posted when suggestions for auto-completion are requested for command input. */ @@ -34,7 +35,7 @@ public class CommandSuggestionEvent extends Event { private final Actor actor; private final String arguments; - private List suggestions = Collections.emptyList(); + private List suggestions = Collections.emptyList(); /** * Create a new instance. @@ -71,9 +72,14 @@ public class CommandSuggestionEvent extends Event { /** * Get the list of suggestions that are to be presented. * + *

+ * Each Substring holds the replacement as the substring, + * and the replacement range as the original substring range. + *

+ * * @return the list of suggestions */ - public List getSuggestions() { + public List getSuggestions() { return suggestions; } @@ -82,7 +88,7 @@ public class CommandSuggestionEvent extends Event { * * @param suggestions the list of suggestions */ - public void setSuggestions(List suggestions) { + public void setSuggestions(List suggestions) { checkNotNull(suggestions); this.suggestions = suggestions; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index e1d293303..bdd904226 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -91,6 +91,7 @@ import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; import com.sk89q.worldedit.internal.command.exception.WorldEditExceptionConverter; +import com.sk89q.worldedit.internal.util.Substring; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.util.eventbus.Subscribe; @@ -125,15 +126,14 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; -import java.util.Arrays; import java.util.List; -import java.util.Locale; import java.util.Optional; import java.util.function.Consumer; import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkNotNull; @@ -419,34 +419,8 @@ public final class PlatformCommandManager { dynamicHandler.setHandler(null); } - public String[] commandDetection(String[] split) { - // Quick script shortcut - if (split[0].matches("^[^/].*\\.js$")) { - String[] newSplit = new String[split.length + 1]; - System.arraycopy(split, 0, newSplit, 1, split.length); - newSplit[0] = "cs"; - newSplit[1] = newSplit[1]; - split = newSplit; - } - - String searchCmd = split[0].toLowerCase(Locale.ROOT); - - // Try to detect the command - if (!commandManager.containsCommand(searchCmd)) { - if (worldEdit.getConfiguration().noDoubleSlash && commandManager.containsCommand("/" + searchCmd)) { - split[0] = "/" + split[0]; - } else if (searchCmd.length() >= 2 && searchCmd.charAt(0) == '/' && commandManager.containsCommand(searchCmd.substring(1))) { - split[0] = split[0].substring(1); - } - } - - return split; - } - - private String[] parseArgs(String input) { - return commandDetection(new CommandArgParser(input.substring(1)) - .parseArgs() - .toArray(String[]::new)); + private Stream parseArgs(String input) { + return new CommandArgParser(CommandArgParser.spaceSplit(input.substring(1))).parseArgs(); } @Subscribe @@ -454,7 +428,9 @@ public final class PlatformCommandManager { Request.reset(); Actor actor = platformManager.createProxyActor(event.getActor()); - String[] split = parseArgs(event.getArguments()); + String[] split = parseArgs(event.getArguments()) + .map(Substring::getSubstring) + .toArray(String[]::new); // No command found! if (!commandManager.containsCommand(split[0])) { @@ -581,13 +557,26 @@ public final class PlatformCommandManager { @Subscribe public void handleCommandSuggestion(CommandSuggestionEvent event) { try { - String[] split = parseArgs(event.getArguments()); - MemoizingValueAccess access = initializeInjectedValues(event::getArguments, event.getActor()); - ImmutableSet suggestions = commandManager.getSuggestions(access, Arrays.asList(split)); + String arguments = event.getArguments(); + List split = parseArgs(arguments).collect(Collectors.toList()); + List argStrings = split.stream() + .map(Substring::getSubstring) + .collect(Collectors.toList()); + MemoizingValueAccess access = initializeInjectedValues(() -> arguments, event.getActor()); + ImmutableSet suggestions = commandManager.getSuggestions(access, argStrings); - log.debug("For input: {}", event.getArguments()); - log.debug("I would suggest this: {}", suggestions); - // TODO send back suggestions + event.setSuggestions(suggestions.stream() + .map(suggestion -> { + Substring original = suggestion.getReplacedArgument() == split.size() + ? Substring.from(arguments, arguments.length() - 1) + : split.get(suggestion.getReplacedArgument()); + // increase original points by 1, for removed `/` in `parseArgs` + return Substring.wrap( + suggestion.getSuggestion(), + original.getStart() + 1, + original.getEnd() + 1 + ); + }).collect(Collectors.toList())); } catch (CommandException e) { event.getActor().printError(e.getMessage()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java index e3605b6f8..c7ce23311 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java @@ -19,86 +19,94 @@ package com.sk89q.worldedit.internal.command; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.sk89q.worldedit.internal.util.Substring; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; import java.util.stream.Stream; public class CommandArgParser { + public static ImmutableList spaceSplit(String string) { + ImmutableList.Builder result = ImmutableList.builder(); + int index = 0; + for (String part : Splitter.on(' ').split(string)) { + result.add(Substring.from(string, index, index + part.length())); + index += part.length() + 1; + } + return result.build(); + } + private enum State { NORMAL, QUOTE } - private final Stream.Builder args = Stream.builder(); - private final StringBuilder currentArg = new StringBuilder(); - private final String input; + private final Stream.Builder args = Stream.builder(); + private final List input; + private final List currentArg = new ArrayList<>(); private int index = 0; private State state = State.NORMAL; - public CommandArgParser(String input) { + public CommandArgParser(List input) { this.input = input; } - public Stream parseArgs() { - for (; index < input.length(); index++) { - char c = input.charAt(index); + public Stream parseArgs() { + for (; index < input.size(); index++) { + Substring nextPart = input.get(index); switch (state) { case NORMAL: - handleNormal(c); + handleNormal(nextPart); break; case QUOTE: - handleQuote(c); + handleQuote(nextPart); } } - finishArg(true); return args.build(); } - private void handleNormal(char c) { - switch (c) { - case '"': - state = State.QUOTE; - break; - case ' ': - finishArg(true); - break; - case '\\': - if (index + 1 < input.length()) { - index++; - } - appendChar(input.charAt(index)); - break; - default: - appendChar(c); + private void handleNormal(Substring part) { + if (part.getSubstring().startsWith("\"")) { + state = State.QUOTE; + currentArg.add(Substring.wrap( + part.getSubstring().substring(1), + part.getStart(), part.getEnd() + )); + } else { + currentArg.add(part); + finishArg(); } } - private void handleQuote(char c) { - switch (c) { - case '"': - state = State.NORMAL; - finishArg(false); - break; - case '\\': - if (index + 1 < input.length()) { - index++; - } - appendChar(input.charAt(index)); - break; - default: - appendChar(c); + private void handleQuote(Substring part) { + if (part.getSubstring().endsWith("\"")) { + state = State.NORMAL; + currentArg.add(Substring.wrap( + part.getSubstring().substring(0, part.getSubstring().length() - 1), + part.getStart(), part.getEnd() + )); + finishArg(); + } else { + currentArg.add(part); } } - private void finishArg(boolean requireText) { - if (currentArg.length() == 0 && requireText) { - return; - } - args.add(currentArg.toString()); - currentArg.setLength(0); - } - - private void appendChar(char c) { - currentArg.append(c); + private void finishArg() { + // Merge the arguments into a single, space-joined, string + // Keep the original start + end points. + int start = currentArg.get(0).getStart(); + int end = Iterables.getLast(currentArg).getEnd(); + args.add(Substring.wrap(currentArg.stream() + .map(Substring::getSubstring) + .collect(Collectors.joining(" ")), + start, end + )); + currentArg.clear(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java index 861c7926d..395153e7e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java @@ -19,15 +19,22 @@ package com.sk89q.worldedit.internal.command; +import com.google.common.collect.Iterables; import com.sk89q.worldedit.extension.platform.PlatformCommandManager; +import com.sk89q.worldedit.internal.util.Substring; import org.enginehub.piston.Command; import org.enginehub.piston.part.SubCommandPart; import java.util.Comparator; +import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; +import static com.google.common.base.Preconditions.checkState; +import static java.util.stream.Collectors.toList; + public class CommandUtil { public static Map getSubCommands(Command currentCommand) { @@ -48,6 +55,43 @@ public class CommandUtil { return BY_CLEAN_NAME; } + /** + * Fix {@code suggestions} to replace the last space-separated word in {@code arguments}. + */ + public static List fixSuggestions(String arguments, List suggestions) { + Substring lastArg = Iterables.getLast(CommandArgParser.spaceSplit(arguments)); + return suggestions.stream() + .map(suggestion -> CommandUtil.suggestLast(lastArg, suggestion)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(toList()); + } + + /** + * Given the last word of a command, mutate the suggestion to replace the last word, if + * possible. + */ + private static Optional suggestLast(Substring last, Substring suggestion) { + if (suggestion.getStart() == last.getEnd()) { + // this suggestion is for the next argument. + if (last.getSubstring().isEmpty()) { + return Optional.of(suggestion.getSubstring()); + } + return Optional.of(last.getSubstring() + " " + suggestion.getSubstring()); + } + StringBuilder builder = new StringBuilder(last.getSubstring()); + int start = suggestion.getStart() - last.getStart(); + int end = suggestion.getEnd() - last.getStart(); + if (start < 0) { + // Quoted suggestion, can't complete it here. + return Optional.empty(); + } + checkState(end <= builder.length(), + "Suggestion ends too late, last=%s, suggestion=", last, suggestion); + builder.replace(start, end, suggestion.getSubstring()); + return Optional.of(builder.toString()); + } + private CommandUtil() { } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/Substring.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/Substring.java new file mode 100644 index 000000000..fa4049cda --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/Substring.java @@ -0,0 +1,97 @@ +/* + * 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.internal.util; + +import java.util.Objects; + +/** + * An explicit substring. Provides the range from which it was taken. + */ +public final class Substring { + + /** + * Take a substring from {@code original}, and {@link #wrap(String, int, int)} it into + * a Substring. + */ + public static Substring from(String original, int start) { + return wrap(original.substring(start), start, original.length()); + } + + /** + * Take a substring from {@code original}, and {@link #wrap(String, int, int)} it into + * a Substring. + */ + public static Substring from(String original, int start, int end) { + return wrap(original.substring(start, end), start, end); + } + + /** + * Wrap the given parameters into a Substring instance. + */ + public static Substring wrap(String substring, int start, int end) { + return new Substring(substring, start, end); + } + + private final String substring; + private final int start; + private final int end; + + private Substring(String substring, int start, int end) { + this.substring = substring; + this.start = start; + this.end = end; + } + + public String getSubstring() { + return substring; + } + + public int getStart() { + return start; + } + + public int getEnd() { + return end; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Substring substring1 = (Substring) o; + return start == substring1.start && + end == substring1.end && + substring.equals(substring1.substring); + } + + @Override + public int hashCode() { + return Objects.hash(substring, start, end); + } + + @Override + public String toString() { + return "Substring{" + + "substring='" + substring + "'" + + ",start=" + start + + ",end=" + end + + "}"; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index 12513b97d..766d7d99c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -99,7 +99,6 @@ public class PropertiesConfiguration extends LocalConfiguration { } superPickaxeDrop = getBool("super-pickaxe-drop-items", superPickaxeDrop); superPickaxeManyDrop = getBool("super-pickaxe-many-drop-items", superPickaxeManyDrop); - noDoubleSlash = getBool("no-double-slash", noDoubleSlash); useInventory = getBool("use-inventory", useInventory); useInventoryOverride = getBool("use-inventory-override", useInventoryOverride); useInventoryCreativeOverride = getBool("use-inventory-creative-override", useInventoryCreativeOverride); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java index 5a657584d..5347eae97 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java @@ -91,8 +91,6 @@ public class YAMLConfiguration extends LocalConfiguration { superPickaxeManyDrop = config.getBoolean( "super-pickaxe.many-drop-items", superPickaxeManyDrop); - noDoubleSlash = config.getBoolean("no-double-slash", noDoubleSlash); - useInventory = config.getBoolean("use-inventory.enable", useInventory); useInventoryOverride = config.getBoolean("use-inventory.allow-override", useInventoryOverride); diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java new file mode 100644 index 000000000..7c75de4a6 --- /dev/null +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java @@ -0,0 +1,51 @@ +/* + * 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.internal.command; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.internal.util.Substring; +import org.junit.Test; + +import static com.sk89q.worldedit.internal.command.CommandArgParser.spaceSplit; +import static org.junit.Assert.assertEquals; + +public class CommandArgParserTest { + @Test + public void testSpaceSplit() { + assertEquals(ImmutableList.of( + Substring.wrap("", 0, 0) + ), spaceSplit("")); + assertEquals(ImmutableList.of( + Substring.wrap("ab", 0, 2) + ), spaceSplit("ab")); + assertEquals(ImmutableList.of( + Substring.wrap("", 0, 0), + Substring.wrap("", 1, 1) + ), spaceSplit(" ")); + assertEquals(ImmutableList.of( + Substring.wrap("a", 0, 1), + Substring.wrap("", 2, 2) + ), spaceSplit("a ")); + assertEquals(ImmutableList.of( + Substring.wrap("a", 0, 1), + Substring.wrap("b", 2, 3) + ), spaceSplit("a b")); + } +} diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 2b0b08b52..62ee93b26 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -24,7 +24,7 @@ configurations.all { Configuration it -> dependencies { compile project(':worldedit-core') - compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' + compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.2' minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}" diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index c6a53795e..f684475e2 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -90,7 +90,7 @@ configure(subprojects + project("core:ap")) { def textVersion = "3.0.0" project("core") { - def pistonVersion = '0.2.0' + def pistonVersion = '0.2.1' dependencies { shade "net.kyori:text-api:$textVersion" diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java index dcaeca0b3..33849e915 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlatform.java @@ -29,6 +29,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.internal.command.CommandUtil; import com.sk89q.worldedit.sponge.config.SpongeConfiguration; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; @@ -144,7 +145,7 @@ class SpongePlatform extends AbstractPlatform implements MultiUserPlatform { public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { CommandSuggestionEvent weEvent = new CommandSuggestionEvent(SpongeWorldEdit.inst().wrapCommandSource(source), command.getName() + " " + arguments); WorldEdit.getInstance().getEventBus().post(weEvent); - return weEvent.getSuggestions(); + return CommandUtil.fixSuggestions(arguments, weEvent.getSuggestions()); } }; ImmutableList.Builder aliases = ImmutableList.builder(); diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java index eb4c64d50..a3bc382f4 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java @@ -98,8 +98,6 @@ public class ConfigurateConfiguration extends LocalConfiguration { superPickaxeDrop = node.getNode("super-pickaxe", "drop-items").getBoolean(superPickaxeDrop); superPickaxeManyDrop = node.getNode("super-pickaxe", "many-drop-items").getBoolean(superPickaxeManyDrop); - noDoubleSlash = node.getNode("no-double-slash").getBoolean(noDoubleSlash); - useInventory = node.getNode("use-inventory", "enable").getBoolean(useInventory); useInventoryOverride = node.getNode("use-inventory", "allow-override").getBoolean(useInventoryOverride); useInventoryCreativeOverride = node.getNode("use-inventory", "creative-mode-overrides").getBoolean(useInventoryCreativeOverride); From 067a570df0359695d24f0419787241726e13f591 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 5 May 2019 22:49:48 -0700 Subject: [PATCH 116/366] Implement basic Forge suggestions --- .../platform/PlatformCommandManager.java | 3 +- .../sk89q/worldedit/forge/CommandWrapper.java | 50 ++++++++++++++++++- worldedit-libs/build.gradle | 2 +- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index bdd904226..b56877590 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -567,8 +567,9 @@ public final class PlatformCommandManager { event.setSuggestions(suggestions.stream() .map(suggestion -> { + int noSlashLength = arguments.length() - 1; Substring original = suggestion.getReplacedArgument() == split.size() - ? Substring.from(arguments, arguments.length() - 1) + ? Substring.from(arguments, noSlashLength, noSlashLength) : split.get(suggestion.getReplacedArgument()); // increase original points by 1, for removed `/` in `parseArgs` return Substring.wrap( diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java index 2f4c650b9..6a15e51dd 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java @@ -22,15 +22,28 @@ package com.sk89q.worldedit.forge; import com.google.common.collect.ImmutableList; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.context.StringRange; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestion; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; +import com.sk89q.worldedit.internal.util.Substring; import net.minecraft.command.CommandSource; import net.minecraft.entity.player.EntityPlayerMP; +import java.util.List; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; import java.util.stream.Stream; +import static net.minecraft.command.Commands.argument; import static net.minecraft.command.Commands.literal; public final class CommandWrapper { @@ -41,8 +54,10 @@ public final class CommandWrapper { ImmutableList.Builder aliases = ImmutableList.builder(); aliases.add(command.getName()).addAll(command.getAliases()); for (String alias : aliases.build()) { - LiteralArgumentBuilder base = literal(alias) - .executes(FAKE_COMMAND); + LiteralArgumentBuilder base = literal(alias).executes(FAKE_COMMAND) + .then(argument("args", StringArgumentType.greedyString()) + .suggests(CommandWrapper::suggest) + .executes(FAKE_COMMAND)); if (command.getCondition().as(PermissionCondition.class) .filter(p -> p.getPermissions().size() > 0).isPresent()) { base.requires(requirementsFor(command)); @@ -73,4 +88,35 @@ public final class CommandWrapper { }; } + private static CompletableFuture suggest(CommandContext context, + SuggestionsBuilder builder) throws CommandSyntaxException { + CommandSuggestionEvent event = new CommandSuggestionEvent( + ForgeAdapter.adaptPlayer(context.getSource().asPlayer()), + builder.getInput() + ); + WorldEdit.getInstance().getEventBus().post(event); + List suggestions = event.getSuggestions(); + + ImmutableList.Builder result = ImmutableList.builder(); + + for (Substring suggestion : suggestions) { + String suggestionText = suggestion.getSubstring(); + // If at end, we are actually suggesting the next argument + // Ensure there is a space! + if (suggestion.getStart() == suggestion.getEnd() + && suggestion.getEnd() == builder.getInput().length() + && !builder.getInput().endsWith(" ")) { + suggestionText = " " + suggestionText; + } + result.add(new Suggestion( + StringRange.between(suggestion.getStart(), suggestion.getEnd()), + suggestionText + )); + } + + return CompletableFuture.completedFuture( + Suggestions.create(builder.getInput(), result.build()) + ); + } + } diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index f684475e2..6549fa81c 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -90,7 +90,7 @@ configure(subprojects + project("core:ap")) { def textVersion = "3.0.0" project("core") { - def pistonVersion = '0.2.1' + def pistonVersion = '0.2.2' dependencies { shade "net.kyori:text-api:$textVersion" From 9a5d45deed5de392ce1a8922d0c20ad77e674127 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 6 May 2019 18:33:21 +1000 Subject: [PATCH 117/366] Fixed direction error --- .../sk89q/worldedit/command/argument/DirectionConverter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java index aacfe4bf5..78d702aa9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java @@ -101,7 +101,7 @@ public class DirectionConverter implements ArgumentConverter { return SuccessfulConversion.fromSingle(includeDiagonals ? worldEdit.getDiagonalDirection(player, argument) : worldEdit.getDirection(player, argument)); - } catch (UnknownDirectionException e) { + } catch (Exception e) { return FailedConversion.from(e); } } From db98cdad0b87b060307b86c03eaa1be181d0f704 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 6 May 2019 09:11:15 -0400 Subject: [PATCH 118/366] Update text-adapters to 3.0.1 Should fix shading issues. --- worldedit-libs/build.gradle | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 6549fa81c..a889835d9 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -88,8 +88,9 @@ configure(subprojects + project("core:ap")) { build.dependsOn(jar, sourcesJar) } -def textVersion = "3.0.0" +def textExtrasVersion = "3.0.1" project("core") { + def textVersion = "3.0.0" def pistonVersion = '0.2.2' dependencies { @@ -121,7 +122,7 @@ project("bukkit") { } } dependencies { - shade "net.kyori:text-adapter-bukkit:$textVersion" + shade "net.kyori:text-adapter-bukkit:$textExtrasVersion" } } project("sponge") { @@ -132,7 +133,7 @@ project("sponge") { } } dependencies { - shade "net.kyori:text-adapter-spongeapi:$textVersion" + shade "net.kyori:text-adapter-spongeapi:$textExtrasVersion" } } From 31d4daf4742b14b63867e9b8acdaf116d65a1b05 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 6 May 2019 19:22:46 -0400 Subject: [PATCH 119/366] Don't compare null BlockStates. --- .../sk89q/worldedit/extension/platform/PlatformManager.java | 2 +- .../main/java/com/sk89q/worldedit/world/block/BlockState.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index f37c9b4a5..f0289957f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -106,7 +106,7 @@ public class PlatformManager { // Make sure that versions are in sync if (firstSeenVersion != null) { if (!firstSeenVersion.equals(platform.getVersion())) { - logger.warn("Multiple ports of WorldEdit are installed but they report different versions ({0} and {1}). " + + logger.warn("Multiple ports of WorldEdit are installed but they report different versions ({} and {}). " + "If these two versions are truly different, then you may run into unexpected crashes and errors.", new Object[]{ firstSeenVersion, platform.getVersion() }); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index d71430c52..5b276badb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -145,6 +145,9 @@ public class BlockState implements BlockStateHolder { @Override public boolean equalsFuzzy(BlockStateHolder o) { + if (null == o) { + return false; + } if (this == o) { // Added a reference equality check for speediness return true; From c169d8f2583f549ec35f68171a4b1b1e2fb045e8 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 9 May 2019 10:28:08 -0400 Subject: [PATCH 120/366] Re-use command manager service. --- .../extension/platform/PlatformCommandManager.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index b56877590..d1a53d763 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -151,6 +151,7 @@ public final class PlatformCommandManager { private final WorldEdit worldEdit; private final PlatformManager platformManager; + private final CommandManagerServiceImpl commandManagerService; private final CommandManager commandManager; private final InjectedValueStore globalInjectedValues; private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler(); @@ -168,7 +169,8 @@ public final class PlatformCommandManager { this.worldEdit = worldEdit; this.platformManager = platformManager; this.exceptionConverter = new WorldEditExceptionConverter(worldEdit); - this.commandManager = new CommandManagerServiceImpl().newCommandManager(); + this.commandManagerService = new CommandManagerServiceImpl(); + this.commandManager = commandManagerService.newCommandManager(); this.globalInjectedValues = MapBackedValueStore.create(); this.registration = new CommandRegistrationHandler( ImmutableList.of( @@ -253,8 +255,7 @@ public final class PlatformCommandManager { cmd.description(TextComponent.of(desc)); cmd.action(Command.Action.NULL_ACTION); - CommandManager manager = DefaultCommandManagerService.getInstance() - .newCommandManager(); + CommandManager manager = commandManagerService.newCommandManager(); this.registration.register( manager, registration, From e2e903ca5ea58e592d2fae3a7230ae35301b7e9b Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 9 May 2019 11:14:10 -0400 Subject: [PATCH 121/366] Pass service to brush sub-commands too. --- .../com/sk89q/worldedit/command/ApplyBrushCommands.java | 7 +++---- .../com/sk89q/worldedit/command/PaintBrushCommands.java | 7 +++---- .../extension/platform/PlatformCommandManager.java | 5 ++--- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java index f9ceadd3e..25c1dbdc1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java @@ -39,8 +39,8 @@ import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandManagerService; import org.enginehub.piston.CommandParameters; -import org.enginehub.piston.DefaultCommandManagerService; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -66,13 +66,12 @@ public class ApplyBrushCommands { .ofTypes(ImmutableList.of(Key.of(double.class))) .build(); - public static void register(CommandManager commandManager, CommandRegistrationHandler registration) { + public static void register(CommandManagerService service, CommandManager commandManager, CommandRegistrationHandler registration) { commandManager.register("apply", builder -> { builder.description(TextComponent.of("Apply brush, apply a function to every block")); builder.action(org.enginehub.piston.Command.Action.NULL_ACTION); - CommandManager manager = DefaultCommandManagerService.getInstance() - .newCommandManager(); + CommandManager manager = service.newCommandManager(); registration.register( manager, ApplyBrushCommandsRegistration.builder(), diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java index cc53ec5b8..e3c92236b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java @@ -39,8 +39,8 @@ import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandManagerService; import org.enginehub.piston.CommandParameters; -import org.enginehub.piston.DefaultCommandManagerService; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -71,13 +71,12 @@ public class PaintBrushCommands { .ofTypes(ImmutableList.of(Key.of(double.class))) .build(); - public static void register(CommandManager commandManager, CommandRegistrationHandler registration) { + public static void register(CommandManagerService service, CommandManager commandManager, CommandRegistrationHandler registration) { commandManager.register("paint", builder -> { builder.description(TextComponent.of("Paint brush, apply a function to a surface")); builder.action(org.enginehub.piston.Command.Action.NULL_ACTION); - CommandManager manager = DefaultCommandManagerService.getInstance() - .newCommandManager(); + CommandManager manager = service.newCommandManager(); registration.register( manager, PaintBrushCommandsRegistration.builder(), diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index d1a53d763..09f34dbd0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -104,7 +104,6 @@ import com.sk89q.worldedit.world.World; import org.enginehub.piston.ColorConfig; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; -import org.enginehub.piston.DefaultCommandManagerService; import org.enginehub.piston.converter.ArgumentConverters; import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.CommandExecutionException; @@ -300,8 +299,8 @@ public final class PlatformCommandManager { BrushCommandsRegistration.builder(), new BrushCommands(worldEdit), manager -> { - PaintBrushCommands.register(manager, registration); - ApplyBrushCommands.register(manager, registration); + PaintBrushCommands.register(commandManagerService, manager, registration); + ApplyBrushCommands.register(commandManagerService, manager, registration); } ); registerSubCommands( From 56908a7d621646a4a6e239099dd816ba3698718f Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 9 May 2019 16:59:06 -0400 Subject: [PATCH 122/366] Update to final Sponge schem v2 spec. Read lenient, write strict. --- .../sk89q/worldedit/command/ClipboardCommands.java | 8 +------- .../extent/clipboard/io/SpongeSchematicReader.java | 5 ++++- .../extent/clipboard/io/SpongeSchematicWriter.java | 13 ++++++------- 3 files changed, 11 insertions(+), 15 deletions(-) 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 01d1a1fb9..c63397fb0 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 @@ -61,12 +61,6 @@ import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class ClipboardCommands { - /** - * Create a new instance. - */ - public ClipboardCommands() { - } - @Command( name = "/copy", desc = "Copy the selection to the clipboard" @@ -78,7 +72,7 @@ public class ClipboardCommands { boolean copyEntities, @Switch(name = 'b', desc = "Also copy biomes") boolean copyBiomes, - @ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "") + @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air", def = "") Mask mask) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); clipboard.setOrigin(session.getPlacementPosition(player)); 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 4d33e82b7..d42d76afd 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 @@ -172,7 +172,10 @@ public class SpongeSchematicReader extends NBTSchematicReader { byte[] blocks = requireTag(schematic, "BlockData", ByteArrayTag.class).getValue(); Map> tileEntitiesMap = new HashMap<>(); - ListTag tileEntities = getTag(schematic, "TileEntities", ListTag.class); + ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class); + if (tileEntities == null) { + tileEntities = getTag(schematic, "TileEntities", ListTag.class); + } if (tileEntities != null) { List> tileEntityTags = tileEntities.getValue().stream() .map(tag -> (CompoundTag) tag) 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 f9d9248a6..2ed06cc03 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 @@ -21,7 +21,6 @@ package com.sk89q.worldedit.extent.clipboard.io; import static com.google.common.base.Preconditions.checkNotNull; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.CompoundTag; @@ -52,6 +51,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -85,9 +85,8 @@ public class SpongeSchematicWriter implements ClipboardWriter { * * @param clipboard The clipboard * @return The schematic map - * @throws IOException If an error occurs */ - private Map write2(Clipboard clipboard) throws IOException { + private Map write2(Clipboard clipboard) { Region region = clipboard.getRegion(); BlockVector3 origin = clipboard.getOrigin(); BlockVector3 min = region.getMinimumPoint(); @@ -190,7 +189,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { schematic.put("Palette", new CompoundTag(paletteTag)); schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray())); - schematic.put("TileEntities", new ListTag(CompoundTag.class, tileEntities)); + schematic.put("BlockEntities", new ListTag(CompoundTag.class, tileEntities)); // version 2 stuff if (clipboard.hasBiomes()) { @@ -265,7 +264,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { values.put("Rotation", writeRotation(e.getLocation())); return new CompoundTag(values); - }).filter(e -> e != null).collect(Collectors.toList()); + }).filter(Objects::nonNull).collect(Collectors.toList()); if (entities.isEmpty()) { return; } @@ -273,7 +272,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { } private Tag writeVector(Vector3 vector) { - List list = new ArrayList(); + List list = new ArrayList<>(); list.add(new DoubleTag(vector.getX())); list.add(new DoubleTag(vector.getY())); list.add(new DoubleTag(vector.getZ())); @@ -281,7 +280,7 @@ public class SpongeSchematicWriter implements ClipboardWriter { } private Tag writeRotation(Location location) { - List list = new ArrayList(); + List list = new ArrayList<>(); list.add(new FloatTag(location.getYaw())); list.add(new FloatTag(location.getPitch())); return new ListTag(FloatTag.class, list); From 389671b43b9f63501e129e6a3616d1255de11822 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Fri, 10 May 2019 03:39:29 -0700 Subject: [PATCH 123/366] Apply eclipse plugin to prevent crash in FG --- worldedit-forge/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 62ee93b26..8b57ef74a 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -11,6 +11,7 @@ buildscript { } } +apply plugin: 'eclipse' apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.13.2" From a2b67f8ddb91bbac246dc3d5161acf4f1aa19526 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Fri, 10 May 2019 05:01:01 -0700 Subject: [PATCH 124/366] Re-write EventBus to be faster --- .../annotation/RequiresNewerGuava.java | 33 ----- .../worldedit/util/eventbus/EventBus.java | 115 +++++++----------- .../util/eventbus/HierarchyCache.java | 21 ++-- .../worldedit/util/eventbus/EventBusTest.java | 53 ++++++++ 4 files changed, 103 insertions(+), 119 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/RequiresNewerGuava.java create mode 100644 worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/RequiresNewerGuava.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/RequiresNewerGuava.java deleted file mode 100644 index 749849ce8..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/RequiresNewerGuava.java +++ /dev/null @@ -1,33 +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 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.internal.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Marks features that should be replaced with Google Guava but cannot - * yet because Bukkit uses such an old version of Guava. - */ -@Retention(RetentionPolicy.SOURCE) -@Documented -public @interface RequiresNewerGuava { -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java index d97c090ea..1121b6193 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/eventbus/EventBus.java @@ -19,11 +19,9 @@ package com.sk89q.worldedit.util.eventbus; +import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; import com.google.common.collect.SetMultimap; -import com.google.common.eventbus.DeadEvent; -import com.sk89q.worldedit.internal.annotation.RequiresNewerGuava; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,11 +29,11 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import static com.google.common.base.Preconditions.checkNotNull; @@ -46,17 +44,15 @@ import static com.google.common.base.Preconditions.checkNotNull; *

This class is based on Guava's {@link EventBus} but priority is supported * and events are dispatched at the time of call, rather than being queued up. * This does allow dispatching during an in-progress dispatch.

- * - *

This implementation utilizes naive synchronization on all getter and - * setter methods. Dispatch does not occur when a lock has been acquired, - * however.

*/ -public class EventBus { +public final class EventBus { private final Logger logger = LoggerFactory.getLogger(EventBus.class); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final SetMultimap, EventHandler> handlersByType = - Multimaps.newSetMultimap(new HashMap<>(), this::newHandlerSet); + HashMultimap.create(); /** * Strategy for finding handler methods in registered objects. Currently, @@ -65,7 +61,6 @@ public class EventBus { */ private final SubscriberFindingStrategy finder = new AnnotatedSubscriberFinder(); - @RequiresNewerGuava private HierarchyCache flattenHierarchyCache = new HierarchyCache(); /** @@ -74,10 +69,15 @@ public class EventBus { * @param clazz the event class to register * @param handler the handler to register */ - public synchronized void subscribe(Class clazz, EventHandler handler) { + public void subscribe(Class clazz, EventHandler handler) { checkNotNull(clazz); checkNotNull(handler); - handlersByType.put(clazz, handler); + lock.writeLock().lock(); + try { + handlersByType.put(clazz, handler); + } finally { + lock.writeLock().unlock(); + } } /** @@ -85,9 +85,14 @@ public class EventBus { * * @param handlers a map of handlers */ - public synchronized void subscribeAll(Multimap, EventHandler> handlers) { + public void subscribeAll(Multimap, EventHandler> handlers) { checkNotNull(handlers); - handlersByType.putAll(handlers); + lock.writeLock().lock(); + try { + handlersByType.putAll(handlers); + } finally { + lock.writeLock().unlock(); + } } /** @@ -96,10 +101,15 @@ public class EventBus { * @param clazz the class * @param handler the handler */ - public synchronized void unsubscribe(Class clazz, EventHandler handler) { + public void unsubscribe(Class clazz, EventHandler handler) { checkNotNull(clazz); checkNotNull(handler); - handlersByType.remove(clazz, handler); + lock.writeLock().lock(); + try { + handlersByType.remove(clazz, handler); + } finally { + lock.writeLock().unlock(); + } } /** @@ -107,15 +117,15 @@ public class EventBus { * * @param handlers a map of handlers */ - public synchronized void unsubscribeAll(Multimap, EventHandler> handlers) { + public void unsubscribeAll(Multimap, EventHandler> handlers) { checkNotNull(handlers); - for (Map.Entry, Collection> entry : handlers.asMap().entrySet()) { - Set currentHandlers = getHandlersForEventType(entry.getKey()); - Collection eventMethodsInListener = entry.getValue(); - - if (currentHandlers != null &&!currentHandlers.containsAll(entry.getValue())) { - currentHandlers.removeAll(eventMethodsInListener); + lock.writeLock().lock(); + try { + for (Map.Entry, Collection> entry : handlers.asMap().entrySet()) { + handlersByType.get(entry.getKey()).removeAll(entry.getValue()); } + } finally { + lock.writeLock().unlock(); } } @@ -146,25 +156,23 @@ public class EventBus { * successfully after the event has been posted to all handlers, and * regardless of any exceptions thrown by handlers. * - *

If no handlers have been subscribed for {@code event}'s class, and - * {@code event} is not already a {@link DeadEvent}, it will be wrapped in a - * DeadEvent and reposted. - * * @param event event to post. */ public void post(Object event) { List dispatching = new ArrayList<>(); - synchronized (this) { - Set> dispatchTypes = flattenHierarchy(event.getClass()); - + Set> dispatchTypes = flattenHierarchyCache.get(event.getClass()); + lock.readLock().lock(); + try { for (Class eventType : dispatchTypes) { - Set wrappers = getHandlersForEventType(eventType); + Set wrappers = handlersByType.get(eventType); if (wrappers != null && !wrappers.isEmpty()) { dispatching.addAll(wrappers); } } + } finally { + lock.readLock().unlock(); } Collections.sort(dispatching); @@ -175,14 +183,12 @@ public class EventBus { } /** - * Dispatches {@code event} to the handler in {@code handler}. This method - * is an appropriate override point for subclasses that wish to make - * event delivery asynchronous. + * Dispatches {@code event} to the handler in {@code handler}. * * @param event event to dispatch. * @param handler handler that will call the handler. */ - protected void dispatch(Object event, EventHandler handler) { + private void dispatch(Object event, EventHandler handler) { try { handler.handleEvent(event); } catch (InvocationTargetException e) { @@ -190,39 +196,4 @@ public class EventBus { } } - /** - * Retrieves a mutable set of the currently registered handlers for - * {@code type}. If no handlers are currently registered for {@code type}, - * this method may either return {@code null} or an empty set. - * - * @param type type of handlers to retrieve. - * @return currently registered handlers, or {@code null}. - */ - synchronized Set getHandlersForEventType(Class type) { - return handlersByType.get(type); - } - - /** - * Creates a new Set for insertion into the handler map. This is provided - * as an override point for subclasses. The returned set should support - * concurrent access. - * - * @return a new, mutable set for handlers. - */ - protected synchronized Set newHandlerSet() { - return new HashSet<>(); - } - - /** - * Flattens a class's type hierarchy into a set of Class objects. The set - * will include all superclasses (transitively), and all interfaces - * implemented by these superclasses. - * - * @param concreteClass class whose type hierarchy will be retrieved. - * @return {@code clazz}'s complete type hierarchy, flattened and uniqued. - */ - Set> flattenHierarchy(Class concreteClass) { - return flattenHierarchyCache.get(concreteClass); - } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/eventbus/HierarchyCache.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/eventbus/HierarchyCache.java index 92f1cb56b..9e0a97813 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/eventbus/HierarchyCache.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/eventbus/HierarchyCache.java @@ -19,34 +19,27 @@ package com.sk89q.worldedit.util.eventbus; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import com.sk89q.worldedit.internal.annotation.RequiresNewerGuava; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.WeakHashMap; /** * Holds a cache of class hierarchy. - * - *

This exists because Bukkit has an ancient version of Guava and the cache - * library in Guava has since changed. */ -@RequiresNewerGuava class HierarchyCache { - private final Map, Set>> cache = new WeakHashMap<>(); + private final LoadingCache, Set>> cache = CacheBuilder.newBuilder() + .weakKeys() + .build(CacheLoader.from(this::build)); public Set> get(Class concreteClass) { - Set> ret = cache.get(concreteClass); - if (ret == null) { - ret = build(concreteClass); - cache.put(concreteClass, ret); - } - return ret; + return cache.getUnchecked(concreteClass); } protected Set> build(Class concreteClass) { diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java new file mode 100644 index 000000000..f3e7e2b6f --- /dev/null +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java @@ -0,0 +1,53 @@ +package com.sk89q.worldedit.util.eventbus; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertEquals; + +public class EventBusTest { + + private static final class Event { + + } + + private static final class Subscriber { + + private final List events = new ArrayList<>(); + + @Subscribe + public void onEvent(Event event) { + events.add(event); + } + + } + + private EventBus eventBus = new EventBus(); + + @Test + public void testRegister() { + Subscriber subscriber = new Subscriber(); + eventBus.register(subscriber); + Event e1 = new Event(); + eventBus.post(e1); + Event e2 = new Event(); + eventBus.post(e2); + assertEquals(asList(e1, e2), subscriber.events); + } + + @Test + public void testUnregister() { + Subscriber subscriber = new Subscriber(); + eventBus.register(subscriber); + Event e1 = new Event(); + eventBus.post(e1); + eventBus.unregister(subscriber); + Event e2 = new Event(); + eventBus.post(e2); + assertEquals(singletonList(e1), subscriber.events); + } +} From aed25fce7c6740ef398bee5079e7877fcfd880c9 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 11 May 2019 21:36:13 -0400 Subject: [PATCH 125/366] Add license. --- .../worldedit/util/eventbus/EventBusTest.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java index f3e7e2b6f..6289301dc 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java @@ -1,3 +1,22 @@ +/* + * 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.util.eventbus; import org.junit.Test; From fab21c3eeac5726e48509762f41e92887789a0a0 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 11 May 2019 21:06:23 -0400 Subject: [PATCH 126/366] Add AsyncCommandBuilder as replacement for AsyncCommandHelper. See full explanation at https://github.com/EngineHub/WorldGuard/pull/408 --- .../worldedit/command/WorldEditCommands.java | 15 +- .../command/util/AsyncCommandBuilder.java | 193 ++++++++++++++++++ .../command/util/AsyncCommandHelper.java | 144 ------------- .../util/paste/ActorCallbackPaste.java | 40 ++-- .../worldedit/util/paste/EngineHubPaste.java | 9 +- .../sk89q/worldedit/util/paste/Pastebin.java | 93 --------- .../sk89q/worldedit/util/paste/Paster.java | 5 +- 7 files changed, 217 insertions(+), 282 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Pastebin.java 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 0d19d1538..dee15226e 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 @@ -67,7 +67,7 @@ public class WorldEditCommands { aliases = { "ver" }, desc = "Get WorldEdit version" ) - public void version(Actor actor) throws WorldEditException { + public void version(Actor actor) { actor.print("WorldEdit version " + WorldEdit.getVersion()); actor.print("https://github.com/EngineHub/worldedit/"); @@ -90,7 +90,7 @@ public class WorldEditCommands { desc = "Reload configuration" ) @CommandPermissions("worldedit.reload") - public void reload(Actor actor) throws WorldEditException { + public void reload(Actor actor) { we.getPlatformManager().queryCapability(Capability.CONFIGURATION).reload(); we.getEventBus().post(new ConfigurationLoadEvent(we.getPlatformManager().queryCapability(Capability.CONFIGURATION).getConfiguration())); actor.print("Configuration reloaded!"); @@ -100,7 +100,7 @@ public class WorldEditCommands { name = "report", desc = "Writes a report on WorldEdit" ) - @CommandPermissions({"worldedit.report"}) + @CommandPermissions("worldedit.report") public void report(Actor actor, @Switch(name = 'p', desc = "Pastebins the report") boolean pastebin) throws WorldEditException { @@ -119,10 +119,7 @@ public class WorldEditCommands { if (pastebin) { actor.checkPermission("worldedit.report.pastebin"); - ActorCallbackPaste.pastebin( - we.getSupervisor(), actor, result, "WorldEdit report: %s.report", - WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter() - ); + ActorCallbackPaste.pastebin(we.getSupervisor(), actor, result, "WorldEdit report: %s.report"); } } @@ -130,7 +127,7 @@ public class WorldEditCommands { name = "cui", desc = "Complete CUI handshake (internal usage)" ) - public void cui(Player player, LocalSession session) throws WorldEditException { + public void cui(Player player, LocalSession session) { session.setCUISupport(true); session.dispatchCUISetup(player); } @@ -141,7 +138,7 @@ public class WorldEditCommands { ) public void tz(Player player, LocalSession session, @Arg(desc = "The timezone to set") - String timezone) throws WorldEditException { + String timezone) { try { ZoneId tz = ZoneId.of(timezone); session.setTimezone(tz); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java new file mode 100644 index 000000000..5d10870b5 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java @@ -0,0 +1,193 @@ +/* + * 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.command.util; + +import com.google.common.base.Strings; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; +import com.sk89q.worldedit.util.formatting.component.ErrorFormat; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import com.sk89q.worldedit.util.task.FutureForwardingTask; +import com.sk89q.worldedit.util.task.Supervisor; +import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.exception.CommandExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nullable; +import java.util.concurrent.Callable; +import java.util.function.Consumer; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +public final class AsyncCommandBuilder { + + private static final Logger logger = LoggerFactory.getLogger(AsyncCommandBuilder.class); + + private final Callable callable; + private final Actor sender; + + @Nullable + private Supervisor supervisor; + @Nullable + private String description; + @Nullable + private String delayMessage; + + @Nullable + private Component successMessage; + @Nullable + private Consumer consumer; + + @Nullable + private Component failureMessage; + @Nullable + private ExceptionConverter exceptionConverter; + + private AsyncCommandBuilder(Callable callable, Actor sender) { + checkNotNull(callable); + checkNotNull(sender); + this.callable = callable; + this.sender = sender; + } + + public static AsyncCommandBuilder wrap(Callable callable, Actor sender) { + return new AsyncCommandBuilder<>(callable, sender); + } + + public AsyncCommandBuilder registerWithSupervisor(Supervisor supervisor, String description) { + this.supervisor = checkNotNull(supervisor); + this.description = checkNotNull(description); + return this; + } + + public AsyncCommandBuilder sendMessageAfterDelay(String message) { + this.delayMessage = checkNotNull(message); + return this; + } + + public AsyncCommandBuilder onSuccess(@Nullable Component message, @Nullable Consumer consumer) { + checkArgument(message != null || consumer != null, "Can't have null message AND consumer"); + this.successMessage = message; + this.consumer = consumer; + return this; + } + + public AsyncCommandBuilder onSuccess(@Nullable String message, @Nullable Consumer consumer) { + checkArgument(message != null || consumer != null, "Can't have null message AND consumer"); + this.successMessage = message == null ? null : TextComponent.of(message, TextColor.LIGHT_PURPLE); + this.consumer = consumer; + return this; + } + + public AsyncCommandBuilder onFailure(@Nullable Component message, @Nullable ExceptionConverter exceptionConverter) { + checkArgument(message != null || exceptionConverter != null, "Can't have null message AND exceptionConverter"); + this.failureMessage = message; + this.exceptionConverter = exceptionConverter; + return this; + } + + public AsyncCommandBuilder onFailure(@Nullable String message, @Nullable ExceptionConverter exceptionConverter) { + checkArgument(message != null || exceptionConverter != null, "Can't have null message AND exceptionConverter"); + this.failureMessage = message == null ? null : ErrorFormat.wrap(message); + this.exceptionConverter = exceptionConverter; + return this; + } + + public ListenableFuture buildAndExec(ListeningExecutorService executor) { + final ListenableFuture future = checkNotNull(executor).submit(this::runTask); + if (delayMessage != null) { + FutureProgressListener.addProgressListener(future, sender, delayMessage); + } + if (supervisor != null && description != null) { + supervisor.monitor(FutureForwardingTask.create(future, description, sender)); + } + return future; + } + + private T runTask() { + T result = null; + try { + result = callable.call(); + if (consumer != null) { + consumer.accept(result); + } + if (successMessage != null) { + sender.print(successMessage); + } + } catch (Exception orig) { + Component failure = failureMessage != null ? failureMessage : TextComponent.of("An error occurred"); + try { + if (exceptionConverter != null) { + try { + exceptionConverter.convert(orig); + } catch (CommandException converted) { + Component message; + + // TODO remove this once WG migrates to piston and can use piston exceptions everywhere + message = tryExtractOldCommandException(converted); + + if (message == null) { + if (Strings.isNullOrEmpty(converted.getMessage())) { + message = TextComponent.of("Unknown error."); + } else { + message = converted.getRichMessage(); + } + } + sender.print(failure.append(TextComponent.of(": ")).append(message)); + } + } else { + throw orig; + } + } catch (Throwable unknown) { + sender.print(failure.append(TextComponent.of(": Unknown error. Please see console."))); + logger.error("Uncaught exception occurred in task: " + description, orig); + } + } + return result; + } + + // this is needed right now since worldguard is still on the 2011 command framework which throws and converts + // com.sk89q.minecraft.util.commands.CommandException. the ExceptionConverter currently expects converted + // exceptions to be org.enginehub.piston.CommandException, throw it wraps the resulting InvocationTargetException in + // a CommandExecutionException. here, we unwrap those layers to retrieve the original WG error message + private Component tryExtractOldCommandException(CommandException converted) { + Component message = null; + if (converted instanceof CommandExecutionException) { + Throwable parentCause = converted; + while ((parentCause = parentCause.getCause()) != null) { + if (parentCause instanceof com.sk89q.minecraft.util.commands.CommandException) { + final String msg = parentCause.getMessage(); + if (!Strings.isNullOrEmpty(msg)) { + message = TextComponent.of(msg); + } + break; + } + } + } + return message; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java deleted file mode 100644 index 842cd5752..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandHelper.java +++ /dev/null @@ -1,144 +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 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.command.util; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; -import com.sk89q.worldedit.util.task.FutureForwardingTask; -import com.sk89q.worldedit.util.task.Supervisor; -import com.sk89q.worldedit.world.World; - -import javax.annotation.Nullable; -import java.util.concurrent.ForkJoinPool; - -public class AsyncCommandHelper { - - private final ListenableFuture future; - private final Supervisor supervisor; - private final Actor sender; - private final ExceptionConverter exceptionConverter; - @Nullable - private Object[] formatArgs; - - private AsyncCommandHelper(ListenableFuture future, Supervisor supervisor, Actor sender, ExceptionConverter exceptionConverter) { - checkNotNull(future); - checkNotNull(supervisor); - checkNotNull(sender); - checkNotNull(exceptionConverter); - - this.future = future; - this.supervisor = supervisor; - this.sender = sender; - this.exceptionConverter = exceptionConverter; - } - - public AsyncCommandHelper formatUsing(Object... args) { - this.formatArgs = args; - return this; - } - - private String format(String message) { - if (formatArgs != null) { - return String.format(message, formatArgs); - } else { - return message; - } - } - - public AsyncCommandHelper registerWithSupervisor(String description) { - supervisor.monitor( - FutureForwardingTask.create( - future, format(description), sender)); - return this; - } - - public AsyncCommandHelper sendMessageAfterDelay(String message) { - FutureProgressListener.addProgressListener(future, sender, format(message)); - return this; - } - - public AsyncCommandHelper thenRespondWith(String success, String failure) { - // Send a response message - Futures.addCallback( - future, - new MessageFutureCallback.Builder(sender) - .exceptionConverter(exceptionConverter) - .onSuccess(format(success)) - .onFailure(format(failure)) - .build(), - ForkJoinPool.commonPool()); - return this; - } - - public AsyncCommandHelper thenTellErrorsOnly(String failure) { - // Send a response message - Futures.addCallback( - future, - new MessageFutureCallback.Builder(sender) - .exceptionConverter(exceptionConverter) - .onFailure(format(failure)) - .build(), - ForkJoinPool.commonPool()); - return this; - } - - public AsyncCommandHelper forRegionDataLoad(World world, boolean silent) { - checkNotNull(world); - - formatUsing(world.getName()); - registerWithSupervisor("Loading region data for '%s'"); - if (silent) { - thenTellErrorsOnly("Failed to load regions '%s'"); - } else { - sendMessageAfterDelay("(Please wait... loading the region data for '%s')"); - thenRespondWith( - "Loaded region data for '%s'", - "Failed to load regions '%s'"); - } - - return this; - } - - public AsyncCommandHelper forRegionDataSave(World world, boolean silent) { - checkNotNull(world); - - formatUsing(world.getName()); - registerWithSupervisor("Saving region data for '%s'"); - if (silent) { - thenTellErrorsOnly("Failed to save regions '%s'"); - } else { - sendMessageAfterDelay("(Please wait... saving the region data for '%s')"); - thenRespondWith( - "Saved region data for '%s'", - "Failed to load regions '%s'"); - } - - return this; - } - - public static AsyncCommandHelper wrap(ListenableFuture future, Supervisor supervisor, Actor sender, ExceptionConverter exceptionConverter) { - return new AsyncCommandHelper(future, supervisor, sender, exceptionConverter); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java index 0509275f6..1eb51a21f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/ActorCallbackPaste.java @@ -19,22 +19,16 @@ package com.sk89q.worldedit.util.paste; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.sk89q.worldedit.command.util.AsyncCommandHelper; +import com.sk89q.worldedit.command.util.AsyncCommandBuilder; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; import com.sk89q.worldedit.util.task.Supervisor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.net.URL; -import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.Callable; -public class ActorCallbackPaste { +public final class ActorCallbackPaste { - private static final Logger LOGGER = LoggerFactory.getLogger(ActorCallbackPaste.class); + private static final Paster paster = new EngineHubPaste(); private ActorCallbackPaste() { } @@ -48,25 +42,15 @@ public class ActorCallbackPaste { * @param content The content * @param successMessage The message, formatted with {@link String#format(String, Object...)} on success */ - public static void pastebin(Supervisor supervisor, final Actor sender, String content, final String successMessage, final ExceptionConverter exceptionConverter) { - ListenableFuture future = new EngineHubPaste().paste(content); + public static void pastebin(Supervisor supervisor, final Actor sender, String content, final String successMessage) { + Callable task = paster.paste(content); - AsyncCommandHelper.wrap(future, supervisor, sender, exceptionConverter) - .registerWithSupervisor("Submitting content to a pastebin service...") - .sendMessageAfterDelay("(Please wait... sending output to pastebin...)"); - - Futures.addCallback(future, new FutureCallback() { - @Override - public void onSuccess(URL url) { - sender.print(String.format(successMessage, url)); - } - - @Override - public void onFailure(Throwable throwable) { - LOGGER.warn("Failed to submit pastebin", throwable); - sender.printError("Failed to submit to a pastebin. Please see console for the error."); - } - }, ForkJoinPool.commonPool()); + AsyncCommandBuilder.wrap(task, sender) + .registerWithSupervisor(supervisor, "Submitting content to a pastebin service.") + .sendMessageAfterDelay("(Please wait... sending output to pastebin...)") + .onSuccess((String) null, url -> sender.print(String.format(successMessage, url))) + .onFailure("Failed to submit paste", null) + .buildAndExec(Pasters.getExecutor()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java index da6b701fd..ac7484846 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.util.paste; -import com.google.common.util.concurrent.ListenableFuture; import com.sk89q.worldedit.util.net.HttpRequest; import org.json.simple.JSONValue; @@ -35,11 +34,11 @@ public class EngineHubPaste implements Paster { private static final Pattern URL_PATTERN = Pattern.compile("https?://.+$"); @Override - public ListenableFuture paste(String content) { - return Pasters.getExecutor().submit(new PasteTask(content)); + public Callable paste(String content) { + return new PasteTask(content); } - private final class PasteTask implements Callable { + private static final class PasteTask implements Callable { private final String content; private PasteTask(String content) { @@ -50,7 +49,7 @@ public class EngineHubPaste implements Paster { public URL call() throws IOException, InterruptedException { HttpRequest.Form form = HttpRequest.Form.create(); form.add("content", content); - form.add("from", "worldguard"); + form.add("from", "enginehub"); URL url = HttpRequest.url("http://paste.enginehub.org/paste"); String result = HttpRequest.post(url) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Pastebin.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Pastebin.java deleted file mode 100644 index dcbef09b0..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Pastebin.java +++ /dev/null @@ -1,93 +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 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.util.paste; - -import com.google.common.util.concurrent.ListenableFuture; -import com.sk89q.worldedit.util.net.HttpRequest; - -import java.io.IOException; -import java.net.URL; -import java.util.concurrent.Callable; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class Pastebin implements Paster { - - private static final Pattern URL_PATTERN = Pattern.compile("https?://pastebin.com/([^/]+)$"); - - private boolean mungingLinks = true; - - public boolean isMungingLinks() { - return mungingLinks; - } - - public void setMungingLinks(boolean mungingLinks) { - this.mungingLinks = mungingLinks; - } - - @Override - public ListenableFuture paste(String content) { - if (mungingLinks) { - content = content.replaceAll("http://", "http_//"); - } - - return Pasters.getExecutor().submit(new PasteTask(content)); - } - - private final class PasteTask implements Callable { - private final String content; - - private PasteTask(String content) { - this.content = content; - } - - @Override - public URL call() throws IOException, InterruptedException { - HttpRequest.Form form = HttpRequest.Form.create(); - form.add("api_option", "paste"); - form.add("api_dev_key", "4867eae74c6990dbdef07c543cf8f805"); - form.add("api_paste_code", content); - form.add("api_paste_private", "0"); - form.add("api_paste_name", ""); - form.add("api_paste_expire_date", "1W"); - form.add("api_paste_format", "text"); - form.add("api_user_key", ""); - - URL url = HttpRequest.url("http://pastebin.com/api/api_post.php"); - String result = HttpRequest.post(url) - .bodyForm(form) - .execute() - .expectResponseCode(200) - .returnContent() - .asString("UTF-8").trim(); - - Matcher m = URL_PATTERN.matcher(result); - - if (m.matches()) { - return new URL("http://pastebin.com/raw.php?i=" + m.group(1)); - } else if (result.matches("^https?://.+")) { - return new URL(result); - } else { - throw new IOException("Failed to save paste; instead, got: " + result); - } - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Paster.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Paster.java index 7a7d74cac..a65ccd6c1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Paster.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/Paster.java @@ -19,12 +19,11 @@ package com.sk89q.worldedit.util.paste; -import com.google.common.util.concurrent.ListenableFuture; - import java.net.URL; +import java.util.concurrent.Callable; public interface Paster { - ListenableFuture paste(String content); + Callable paste(String content); } From 7b170d81939f8e86ae9b67093ab77c4cd210fc2a Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 12 May 2019 16:01:22 -0400 Subject: [PATCH 127/366] Run schematic-file I/O in a task. --- .../java/com/sk89q/worldedit/WorldEdit.java | 15 ++- .../worldedit/command/SchematicCommands.java | 126 ++++++++++++------ .../worldedit/command/WorldEditCommands.java | 2 +- .../command/util/MessageFutureCallback.java | 114 ---------------- 4 files changed, 100 insertions(+), 157 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index 38c7cbd26..c9e926222 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -21,6 +21,8 @@ package com.sk89q.worldedit; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.BlockInteractEvent; @@ -44,6 +46,7 @@ import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine; import com.sk89q.worldedit.session.SessionManager; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.concurrency.EvenMoreExecutors; import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException; import com.sk89q.worldedit.util.io.file.FilenameException; @@ -102,6 +105,7 @@ public final class WorldEdit { private final PlatformManager platformManager = new PlatformManager(this); private final EditSessionFactory editSessionFactory = new EditSessionFactory.EditSessionFactoryImpl(eventBus); private final SessionManager sessions = new SessionManager(this); + private final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20));; private final Supervisor supervisor = new SimpleSupervisor(); private final BlockFactory blockFactory = new BlockFactory(this); @@ -152,7 +156,7 @@ public final class WorldEdit { } /** - * Get the supervisor. + * Get the supervisor. Internal, not for API use. * * @return the supervisor */ @@ -160,6 +164,15 @@ public final class WorldEdit { return supervisor; } + /** + * Get the executor service. Internal, not for API use. + * + * @return the executor service + */ + public ListeningExecutorService getExecutorService() { + return executorService; + } + /** * Get the block factory from which new {@link BlockStateHolder}s can be * constructed. 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 829af8a9c..fee171716 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 @@ -23,6 +23,7 @@ import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.AsyncCommandBuilder; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; @@ -60,6 +61,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.Callable; import static com.google.common.base.Preconditions.checkNotNull; @@ -113,20 +115,13 @@ public class SchematicCommands { return; } - try (Closer closer = Closer.create()) { - FileInputStream fis = closer.register(new FileInputStream(f)); - BufferedInputStream bis = closer.register(new BufferedInputStream(fis)); - ClipboardReader reader = closer.register(format.getReader(bis)); - - Clipboard clipboard = reader.read(); - session.setClipboard(new ClipboardHolder(clipboard)); - - log.info(player.getName() + " loaded " + f.getCanonicalPath()); - player.print(filename + " loaded. Paste it with //paste"); - } catch (IOException e) { - player.printError("Schematic could not read or it does not exist: " + e.getMessage()); - log.warn("Failed to load schematic: " + e.getMessage()); - } + SchematicLoadTask task = new SchematicLoadTask(player, f, format); + AsyncCommandBuilder.wrap(task, player) + .registerWithSupervisor(worldEdit.getSupervisor(), "Loading schematic " + filename) + .sendMessageAfterDelay("(Please wait... loading schematic.)") + .onSuccess(filename + " loaded. Paste it with //paste", session::setClipboard) + .onFailure("Failed to load schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter()) + .buildAndExec(worldEdit.getExecutorService()); } @Command( @@ -165,42 +160,24 @@ public class SchematicCommands { } } - ClipboardHolder holder = session.getClipboard(); - Clipboard clipboard = holder.getClipboard(); - Transform transform = holder.getTransform(); - Clipboard target; - - // If we have a transform, bake it into the copy - if (!transform.isIdentity()) { - FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform); - target = new BlockArrayClipboard(result.getTransformedRegion()); - target.setOrigin(clipboard.getOrigin()); - Operations.completeLegacy(result.copyTo(target)); - } else { - target = clipboard; - } - // Create parent directories File parent = f.getParentFile(); if (parent != null && !parent.exists()) { if (!parent.mkdirs()) { throw new StopExecutionException(TextComponent.of( - "Could not create folder for schematics!")); + "Could not create folder for schematics!")); } } - try (Closer closer = Closer.create()) { - FileOutputStream fos = closer.register(new FileOutputStream(f)); - BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos)); - ClipboardWriter writer = closer.register(format.getWriter(bos)); - writer.write(target); + ClipboardHolder holder = session.getClipboard(); - log.info(player.getName() + " saved " + f.getCanonicalPath() + (overwrite ? " (overwriting previous file)" : "")); - player.print(filename + " saved" + (overwrite ? " (overwriting previous file)." : ".")); - } catch (IOException e) { - player.printError("Schematic could not written: " + e.getMessage()); - log.warn("Failed to write a saved clipboard", e); - } + SchematicSaveTask task = new SchematicSaveTask(player, f, format, holder, overwrite); + AsyncCommandBuilder.wrap(task, player) + .registerWithSupervisor(worldEdit.getSupervisor(), "Saving schematic " + filename) + .sendMessageAfterDelay("(Please wait... saving schematic.)") + .onSuccess(filename + " saved" + (overwrite ? " (overwriting previous file)." : "."), null) + .onFailure("Failed to load schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter()) + .buildAndExec(worldEdit.getExecutorService()); } @Command( @@ -329,4 +306,71 @@ public class SchematicCommands { return fileList; } + private static class SchematicLoadTask implements Callable { + private final Player player; + private final File file; + private final ClipboardFormat format; + + SchematicLoadTask(Player player, File file, ClipboardFormat format) { + this.player = player; + this.file = file; + this.format = format; + } + + @Override + public ClipboardHolder call() throws Exception { + try (Closer closer = Closer.create()) { + FileInputStream fis = closer.register(new FileInputStream(file)); + BufferedInputStream bis = closer.register(new BufferedInputStream(fis)); + ClipboardReader reader = closer.register(format.getReader(bis)); + + Clipboard clipboard = reader.read(); + log.info(player.getName() + " loaded " + file.getCanonicalPath()); + return new ClipboardHolder(clipboard); + } + } + } + + private static class SchematicSaveTask implements Callable { + private final Player player; + private final File file; + private final ClipboardFormat format; + private final ClipboardHolder holder; + private final boolean overwrite; + + SchematicSaveTask(Player player, File file, ClipboardFormat format, ClipboardHolder holder, boolean overwrite) { + this.player = player; + this.file = file; + this.format = format; + this.holder = holder; + this.overwrite = overwrite; + } + + @Override + public Void call() throws Exception { + Clipboard clipboard = holder.getClipboard(); + Transform transform = holder.getTransform(); + Clipboard target; + + // If we have a transform, bake it into the copy + if (transform.isIdentity()) { + target = clipboard; + } else { + FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform); + target = new BlockArrayClipboard(result.getTransformedRegion()); + target.setOrigin(clipboard.getOrigin()); + Operations.completeLegacy(result.copyTo(target)); + } + + try (Closer closer = Closer.create()) { + FileOutputStream fos = closer.register(new FileOutputStream(file)); + BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos)); + ClipboardWriter writer = closer.register(format.getWriter(bos)); + writer.write(target); + + log.info(player.getName() + " saved " + file.getCanonicalPath() + (overwrite ? " (overwriting previous file)" : "")); + } + return null; + } + } } 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 dee15226e..154f57f52 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 @@ -110,7 +110,7 @@ public class WorldEditCommands { String result = report.toString(); try { - File dest = new File(we.getWorkingDirectoryFile(we.getConfiguration().saveDir), "report.txt"); + File dest = new File(we.getConfiguration().getWorkingDirectory(), "report.txt"); Files.write(result, dest, Charset.forName("UTF-8")); actor.print("WorldEdit report written to " + dest.getAbsolutePath()); } catch (IOException e) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java deleted file mode 100644 index 2a330259e..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/MessageFutureCallback.java +++ /dev/null @@ -1,114 +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 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.command.util; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.util.concurrent.FutureCallback; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.internal.command.exception.ExceptionConverter; -import org.enginehub.piston.exception.CommandException; - -import javax.annotation.Nullable; - -public class MessageFutureCallback implements FutureCallback { - - private final ExceptionConverter exceptionConverter; - private final Actor sender; - @Nullable - private final String success; - @Nullable - private final String failure; - - private MessageFutureCallback(ExceptionConverter exceptionConverter, Actor sender, @Nullable String success, @Nullable String failure) { - this.exceptionConverter = exceptionConverter; - this.sender = sender; - this.success = success; - this.failure = failure; - } - - @Override - public void onSuccess(@Nullable V v) { - if (success != null) { - sender.print(success); - } - } - - @Override - public void onFailure(@Nullable Throwable throwable) { - try { - exceptionConverter.convert(throwable); - } catch (CommandException e) { - String failure = this.failure != null ? this.failure : "An error occurred"; - String message = e.getMessage() != null ? e.getMessage() : "An unknown error occurred. Please see the console!"; - sender.printError(failure + ": " + message); - } - } - - public static class Builder { - private final Actor sender; - @Nullable - private String success; - @Nullable - private String failure; - private ExceptionConverter exceptionConverter; - - public Builder(Actor sender) { - checkNotNull(sender); - - this.sender = sender; - } - - public Builder exceptionConverter(ExceptionConverter exceptionConverter) { - this.exceptionConverter = exceptionConverter; - return this; - } - - public Builder onSuccess(@Nullable String message) { - this.success = message; - return this; - } - - public Builder onFailure(@Nullable String message) { - this.failure = message; - return this; - } - - public MessageFutureCallback build() { - checkNotNull(exceptionConverter); - return new MessageFutureCallback<>(exceptionConverter, sender, success, failure); - } - } - - public static MessageFutureCallback createRegionLoadCallback(ExceptionConverter exceptionConverter, Actor sender) { - return new Builder(sender) - .exceptionConverter(exceptionConverter) - .onSuccess("Successfully load the region data.") - .build(); - } - - public static MessageFutureCallback createRegionSaveCallback(ExceptionConverter exceptionConverter, Actor sender) { - return new Builder(sender) - .exceptionConverter(exceptionConverter) - .onSuccess("Successfully saved the region data.") - .build(); - } - -} From 6765c2896d03eaf7d92bd8537f0ddef89c460201 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 13 May 2019 02:47:05 -0700 Subject: [PATCH 128/366] Bump text-extras to 3.0.2 --- worldedit-libs/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index a889835d9..0ed531354 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -88,7 +88,7 @@ configure(subprojects + project("core:ap")) { build.dependsOn(jar, sourcesJar) } -def textExtrasVersion = "3.0.1" +def textExtrasVersion = "3.0.2" project("core") { def textVersion = "3.0.0" def pistonVersion = '0.2.2' From 93dd956baeb2e0ff49650f87b0fdc8f69db4ca4a Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 13 May 2019 04:04:46 -0700 Subject: [PATCH 129/366] Bump Piston to 0.2.3 for deadlock fix --- worldedit-libs/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 0ed531354..37f503862 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -91,7 +91,7 @@ configure(subprojects + project("core:ap")) { def textExtrasVersion = "3.0.2" project("core") { def textVersion = "3.0.0" - def pistonVersion = '0.2.2' + def pistonVersion = '0.2.3' dependencies { shade "net.kyori:text-api:$textVersion" From 9a913a93f659c14f3f601b882db225a24e2d6c55 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 13 May 2019 17:22:35 -0400 Subject: [PATCH 130/366] Fix throwing uncaught exceptions in AsyncCommandBuilder. --- .../com/sk89q/worldedit/command/util/AsyncCommandBuilder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java index 5d10870b5..f79d3bdd1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java @@ -144,6 +144,7 @@ public final class AsyncCommandBuilder { if (exceptionConverter != null) { try { exceptionConverter.convert(orig); + throw orig; } catch (CommandException converted) { Component message; From 5c97418cca45c56ba9e85f85da77109259c6b3c7 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 13 May 2019 17:38:46 -0400 Subject: [PATCH 131/366] Fix NBT list conversion in 1.14. --- .../bukkit/adapter/impl/Spigot_v1_14_R1.class | Bin 25976 -> 25969 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1.class index da36d279ff8a146504061ac4db0f3b61a0d93491..19794dd5c3be6b9d5b3e1346a63fec7eae690479 100644 GIT binary patch delta 26 icmexyit*zq#tm7TOpNB6b2QE6n3)peH?MU+EeimWp$YB) delta 33 pcmex(it)!O#tm7TOe`Xsb2QE6xH!{OOF}9OQaw{PFLOUF3jp2x45R=6 From 10f7fb6a265a2500babc719fcc7712cc1f885597 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 13 May 2019 17:40:43 -0400 Subject: [PATCH 132/366] Add //br and //brush as aliases. --- .../java/com/sk89q/worldedit/command/ClipboardCommands.java | 2 +- .../worldedit/extension/platform/PlatformCommandManager.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 c63397fb0..8b0e20a1f 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 @@ -143,7 +143,7 @@ public class ClipboardCommands { boolean pasteEntities, @Switch(name = 'b', desc = "Paste biomes if available") boolean pasteBiomes, - @ArgFlag(name = 'm', desc = "Skip blocks matching this mask", def = "") + @ArgFlag(name = 'm', desc = "Only paste blocks matching this mask", def = "") Mask sourceMask) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 09f34dbd0..455ae0403 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -281,7 +281,7 @@ public final class PlatformCommandManager { registerSubCommands( "snapshot", ImmutableList.of("snap"), - "Snapshot commands for saving/loading snapshots", + "Snapshot commands for restoring backups", SnapshotCommandsRegistration.builder(), new SnapshotCommands(worldEdit) ); @@ -294,7 +294,7 @@ public final class PlatformCommandManager { ); registerSubCommands( "brush", - ImmutableList.of("br"), + ImmutableList.of("br", "/brush", "/br"), "Brushing commands", BrushCommandsRegistration.builder(), new BrushCommands(worldEdit), From f9d0d340e7123b4ab2de7d97d44d0881643104f5 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 13 May 2019 23:06:50 -0400 Subject: [PATCH 133/366] Add DFUs. Currently used by //restore. --- .../bukkit/BukkitServerInterface.java | 9 +++++ .../bukkit/adapter/BukkitImplAdapter.java | 9 +++++ .../bukkit/adapter/BukkitImplLoader.java | 2 +- .../impl/DataConverters_1_13_R2_2$1.class | Bin 0 -> 300 bytes ...taConverters_1_13_R2_2$DataConverter.class | Bin 0 -> 446 bytes ...rs_1_13_R2_2$DataConverterArmorStand.class | Bin 0 -> 1362 bytes ...erters_1_13_R2_2$DataConverterBanner.class | Bin 0 -> 2179 bytes ...ters_1_13_R2_2$DataConverterBedBlock.class | Bin 0 -> 3023 bytes ...rters_1_13_R2_2$DataConverterBedItem.class | Bin 0 -> 1474 bytes ...nverters_1_13_R2_2$DataConverterBook.class | Bin 0 -> 3342 bytes ...rs_1_13_R2_2$DataConverterCookedFish.class | Bin 0 -> 1586 bytes ...s_1_13_R2_2$DataConverterDropChances.class | Bin 0 -> 1603 bytes ...erters_1_13_R2_2$DataConverterEntity.class | Bin 0 -> 5995 bytes ...ers_1_13_R2_2$DataConverterEquipment.class | Bin 0 -> 2350 bytes ...ters_1_13_R2_2$DataConverterGuardian.class | Bin 0 -> 1432 bytes ...rters_1_13_R2_2$DataConverterHanging.class | Bin 0 -> 2219 bytes ...erters_1_13_R2_2$DataConverterHealth.class | Bin 0 -> 2448 bytes ...verters_1_13_R2_2$DataConverterHorse.class | Bin 0 -> 1612 bytes ...nverters_1_13_R2_2$DataConverterLang.class | Bin 0 -> 1403 bytes ...rs_1_13_R2_2$DataConverterMaterialId.class | Bin 0 -> 13795 bytes ...ters_1_13_R2_2$DataConverterMinecart.class | Bin 0 -> 2039 bytes ...rs_1_13_R2_2$DataConverterMobSpawner.class | Bin 0 -> 2400 bytes ...ters_1_13_R2_2$DataConverterPotionId.class | Bin 0 -> 4550 bytes ...s_1_13_R2_2$DataConverterPotionWater.class | Bin 0 -> 1826 bytes ...erters_1_13_R2_2$DataConverterRiding.class | Bin 0 -> 1936 bytes ...erters_1_13_R2_2$DataConverterSaddle.class | Bin 0 -> 1777 bytes ...rters_1_13_R2_2$DataConverterShulker.class | Bin 0 -> 1347 bytes ...13_R2_2$DataConverterShulkerBoxBlock.class | Bin 0 -> 1306 bytes ..._13_R2_2$DataConverterShulkerBoxItem.class | Bin 0 -> 2726 bytes ...rs_1_13_R2_2$DataConverterSignText$1.class | Bin 0 -> 2819 bytes ...ters_1_13_R2_2$DataConverterSignText.class | Bin 0 -> 3133 bytes ...ters_1_13_R2_2$DataConverterSkeleton.class | Bin 0 -> 1549 bytes ...ters_1_13_R2_2$DataConverterSpawnEgg.class | Bin 0 -> 3822 bytes ...rs_1_13_R2_2$DataConverterTileEntity.class | Bin 0 -> 2989 bytes ...verters_1_13_R2_2$DataConverterTotem.class | Bin 0 -> 1318 bytes ...nverters_1_13_R2_2$DataConverterUUID.class | Bin 0 -> 1324 bytes ...onverters_1_13_R2_2$DataConverterVBO.class | Bin 0 -> 1102 bytes ...erters_1_13_R2_2$DataConverterZombie.class | Bin 0 -> 1955 bytes ...rs_1_13_R2_2$DataConverterZombieType.class | Bin 0 -> 1618 bytes ...taConverters_1_13_R2_2$DataInspector.class | Bin 0 -> 417 bytes ...s_1_13_R2_2$DataInspectorBlockEntity.class | Bin 0 -> 6401 bytes ...erters_1_13_R2_2$DataInspectorChunks.class | Bin 0 -> 2596 bytes ..._1_13_R2_2$DataInspectorCommandBlock.class | Bin 0 -> 2308 bytes ...erters_1_13_R2_2$DataInspectorEntity.class | Bin 0 -> 2676 bytes ...3_R2_2$DataInspectorEntityPassengers.class | Bin 0 -> 2312 bytes ...nverters_1_13_R2_2$DataInspectorItem.class | Bin 0 -> 1316 bytes ...ters_1_13_R2_2$DataInspectorItemList.class | Bin 0 -> 1326 bytes ...s_1_13_R2_2$DataInspectorLevelPlayer.class | Bin 0 -> 1792 bytes ...R2_2$DataInspectorMobSpawnerMinecart.class | Bin 0 -> 2500 bytes ..._13_R2_2$DataInspectorMobSpawnerMobs.class | Bin 0 -> 2702 bytes ...erters_1_13_R2_2$DataInspectorPlayer.class | Bin 0 -> 1996 bytes ...1_13_R2_2$DataInspectorPlayerVehicle.class | Bin 0 -> 1965 bytes ...ers_1_13_R2_2$DataInspectorStructure.class | Bin 0 -> 2405 bytes ...erters_1_13_R2_2$DataInspectorTagged.class | Bin 0 -> 1491 bytes ...ers_1_13_R2_2$DataInspectorVillagers.class | Bin 0 -> 2662 bytes .../DataConverters_1_13_R2_2$LegacyType.class | Bin 0 -> 3121 bytes ...onverters_1_13_R2_2$WrappedDataFixer.class | Bin 0 -> 4486 bytes .../impl/DataConverters_1_13_R2_2.class | Bin 0 -> 26822 bytes .../adapter/impl/Spigot_v1_13_R1$1.class | Bin 959 -> 959 bytes .../bukkit/adapter/impl/Spigot_v1_13_R1.class | Bin 25603 -> 25718 bytes .../adapter/impl/Spigot_v1_13_R2$1.class | Bin 959 -> 959 bytes .../bukkit/adapter/impl/Spigot_v1_13_R2.class | Bin 25718 -> 25833 bytes .../adapter/impl/Spigot_v1_13_R2_2$1.class | Bin 965 -> 965 bytes .../adapter/impl/Spigot_v1_13_R2_2.class | Bin 25784 -> 26343 bytes .../adapter/impl/Spigot_v1_14_R1$1.class | Bin 959 -> 959 bytes .../bukkit/adapter/impl/Spigot_v1_14_R1.class | Bin 25969 -> 26084 bytes .../extension/platform/AbstractPlatform.java | 5 +++ .../extension/platform/Platform.java | 8 +++++ .../com/sk89q/worldedit/world/DataFixer.java | 34 ++++++++++++++++++ .../worldedit/world/chunk/AnvilChunk13.java | 9 ++--- .../worldedit/world/storage/ChunkStore.java | 15 +++++++- 71 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$1.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverter.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterArmorStand.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBanner.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedBlock.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedItem.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBook.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterCookedFish.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterDropChances.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterEntity.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterEquipment.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterGuardian.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHanging.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHealth.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHorse.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterLang.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMaterialId.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMinecart.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMobSpawner.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterPotionId.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterPotionWater.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterRiding.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSaddle.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterShulker.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterShulkerBoxBlock.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterShulkerBoxItem.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSignText$1.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSignText.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSkeleton.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSpawnEgg.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTileEntity.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTotem.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterUUID.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterVBO.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombie.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombieType.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspector.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorBlockEntity.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorChunks.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorCommandBlock.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntity.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntityPassengers.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorItem.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorItemList.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorLevelPlayer.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorMobSpawnerMinecart.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorMobSpawnerMobs.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayer.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayerVehicle.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorStructure.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorTagged.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorVillagers.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$LegacyType.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$WrappedDataFixer.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2.class create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 34ad4c257..e4707341a 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -28,6 +28,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.registry.Registries; import org.bukkit.Bukkit; import org.bukkit.Server; @@ -75,6 +76,14 @@ public class BukkitServerInterface implements MultiUserPlatform { return -1; } + @Override + public DataFixer getDataFixer() { + if (plugin.getBukkitImplAdapter() != null) { + return plugin.getBukkitImplAdapter().getDataFixer(); + } + return null; + } + @Override public boolean isValidMobType(String type) { final EntityType entityType = EntityType.fromName(type); 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 9ac0fe8de..fce88bd29 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 @@ -23,6 +23,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -47,6 +48,14 @@ public interface BukkitImplAdapter { */ int getDataVersion(); + /** + * Get a data fixer, or null if not supported + * + * @return the data fixer + */ + @Nullable + DataFixer getDataFixer(); + /** * Get the block at the given location. * diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java index 612290995..950e4f862 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java @@ -157,7 +157,7 @@ public class BukkitImplLoader { if (BukkitImplAdapter.class.isAssignableFrom(cls)) { return (BukkitImplAdapter) cls.newInstance(); } else { - log.warn("Failed to load the Bukkit adapter class '" + className + + log.debug("Failed to load the Bukkit adapter class '" + className + "' because it does not implement " + BukkitImplAdapter.class.getCanonicalName()); } } catch (ClassNotFoundException e) { diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$1.class new file mode 100644 index 0000000000000000000000000000000000000000..a4b5d0ff852132c361b7f085b65cc5992df9f189 GIT binary patch literal 300 zcmbu4K~4fe5Ji6}Iyjg(7cgPr+Rh*g*bxB}7ls55FllBgI84(G-3{K21qa|zhT;IO ztV;ctN-F=S&cDYKfId12k^~Qgbm8{Coy-Ya^qYkkm! zr>QNC3$I;!QqX#~2`TX9nLW^2@6<}W$n@zYxN xW1~ahK*+9n%4oY%v*nu0NErP$ChLN5Bi~=^RvNOka3^fxUbHQf$_)vTwJ*gsQ!D@g literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverter.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverter.class new file mode 100644 index 0000000000000000000000000000000000000000..acd6dba8e13643a4757987f27ab7e13e8ab7e83a GIT binary patch literal 446 zcmbtR!AiqG5Pef?V`E$W0dF4Ki%Y8q#fumb3Q|FfN5eK5Lz-kaZZ`4XJoo{Al((owIXbcCv$=qY1Oc?g!}Q8Vk?SN zab)C!6%`xDh-Mm255t?8Se!4HG6{51>RQF8lfSJK{99d{h%eKe345)V;8WW<3cp0c z*}+;i(!+?bh;$*U?D*tSJZY219H&;S>MV00V_8~fE-lJj{B~;p8$lTU=m&G9*aW$( zDy|5-t+L3aO2qYQ&5_IG?7tRz1VYDs0_b#I=I8Y+@ILAm1`d6POg!WvFZy0f$WX{N>H4x9a?fJWHat(rqQiqgkl}90^j#yUFR$zy zFMa7)!m>l7+N{@!aEmtxZrE4Ti!= zVT05xv%bk2-L9s~ep8y_ksbAYs;}UlP89Zdi)$Ff5JUR75ezZgQekMgiFp+Z8Wyoc zV=j|7FVt`gw@KRMvM!{CJ6Kk+!tnHe&4pnk%F}STS2G@0_kEgdJ^QPLv(rs}Kf2%8Z5P43X1kM%m~RK1$pr8!Zcb>DXcr}gYJ zI*LR_2`OB^MWg?t0lm=&f7?DxBl=Cy^Q3=9oIYA2l7@*hh%%xBvtPhI6BEM-ory@P zyuv8)TE_r7#zTM8;VL$-e6jJi;VKF9cR4bs~d;B;yflP(uFpP aW$1dUo!~{BA*z#{#wiXAQ^aoQD>5S&pCTOf9IUt-~amcHvlhT zA&w_7s35IiC{Fy#alC?86`YaGS$PaA7*TLe!FkDz%Hx89iwa(oWG0R=j4POs_a!NL zT^?`5a5;u6G2|Gc=S>My=9CPE)|_b@Q_Gct;pRobB8irBio%)|t||G3 zko$|K$Ivz|d@<(OD~9VEZbsO);WDUMd5>Ab^9)j&%@v)B?k$};drMz+T&rZ1OkXc7 zFD=m}N}@`px>>1OdXqPAZg6gJXzpryF5TVqpdMy~;Yiu=<&#;%^-RYOD#Rie6s+L$Iot)#+qxbPa3^!EF;RG2Z zQ`D~>8E#&MKtV+jlmPk4{~r@ZCCl=4OW0+7x^UAdQj@3t+ep-#ChQsd4l=O}EwlqO zzH8b9?8#*ApM>i|8tGl4rn~vDEdZgz%E%l=Ct{7|63;DGwA%1M9 zS|e6g>K&qlwuY1;vxnM&w@i^WE;=s3-;~`}i8OSIx2>{QW;5~)7b7=v`xq|lkyUno zX*Je2xt}i8gK^LNkO1pQQiMHv5p|7oM^SKfM@YMaSSiu1f9}&fNp8b zkA}OyqkE_A$2)BKwrw|FtlP3OI7I<|(n2XMTm!EmvVpHtS~L-_A+~|fh^#@G?9*Br zl8=Za$yC1+QQW9PZPOG?Yh(B;{e=$+gx5*^$dr0j<=K7>;yC zYBUI4E(kC*U+(nmLOt#U!4gOYENxa*5Lr9%h0I!PteKlp^JZt z6yHFae~$C~J|_7CT;mThPcbb1C06+(+~HqgoqvOS{4pNzZ}EtKkH`E6Z1SH2v_=V$ zRcg*joI(WiIE^HF2&Xh|qnD^Ky0DHEQ6Y(3164`&k&L0Aq^$`5iS-x;=%@Wb%?nYF YWou58F(}~>%|aH>Ax_hf#bmVQZ@b$%*8l(j literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedBlock.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedBlock.class new file mode 100644 index 0000000000000000000000000000000000000000..45b1ab20b47f84c877d85e6f08f33b58eabc3bc4 GIT binary patch literal 3023 zcmcImS!`QH6g^`*eq-llGZ-)hVkpq0ZQ>?{&?cn?rv(B|3M5Szmh{VIx4YQVvAz8N^A?`CfuxsTO@8(i(?Yo6*V-Z z6{UVgBCA+aVqDRj#108dX-#OD451Zyi9$VW6vLRpP7SUGPs6l;Fa*v|6`fqdm@+au z%tXGJ%UO0#(Mu*0Db7r%PawF)vMq0|fWNJMR3Ok_%$fpCDa$s8rVDA)88Om%u0&GB zjFBHT981mT7X#i7%N2;OH$0=iXwR6AXF5qUo6Hw8lLGpHZJSPi-f&%$Vp~#~Vj%Q=$jbn}&MPttN z)ZVD+xK`1wL^B|uWvYh~xV0^1n_i;8uriJ@?j>B);c*i)^R^R1$&nEw*Iz756{qcN zU;C+v3;3)qCY?Tg6J&go9GdL3=NUN$U9q`Rpz~C%iu|9WuVmkC)@S zi4(z$|G}j?lErUAAY466-f}&Gr3*Soin7dY{qLHz7cxs3bIPkEIhvXbkHYY9aoWk4S6K>k z=bm)kC*Yt{`PFeDE@BQ+=8T!wQNnKeEL~r8bwZvORFUv_u+mr zJfWD?@ctGAF`gx;$E{MFSdXVwRk_RKc@=Pcyyz4RFJ3Tq z$J1uKV7V@p%{ghfW?wsdN$WqnX)OF*hQlYIX3X@t`0or18n(fQkrAsa ztUQv`Xlq}1wH>XwDRM-&F^g03ixj#z>j^7D;JYXkP6berLRN0LdJ(B9D{06 zeu6ggdQ|}JSk9S12Rb<_Wkr>8pe10wNP42~rzhwJj_W3{qN?kA9(8D;&S!zkmqmPK z_=h?ofimiP0v(Z{qIDe+tvOtV>X=Q|;!wWGjD$A(v4aGtcy^MyQ zFqy_OntJQ~J$h7+)xYx`N-g5qSbbDq*@C&fTIpFBQN6ioZ%+e>oK;+7RM#p@)7xm? z`Z`*An`6z9NaVCKPA3zMHbetjX?q!GaCT<2F&aKTJ1g20t(%_(W6fp6Ht*BL{<-`1 zNse3gqjBg}EQ*}-CeHO?*~<*whl4o8yYN@iY-17Ad;~uEIYROaw8$?JlV4%6{2Cqd z8}!O=(J#M4N`8+`@&{~}KVql+2_^Y6?v}scVfibbmPhf7oWp?-@McKhy^s$dQ1&D0 z9}Gzx3I%aEq~S;?T)C1mB7B=RqYK?=;Bz#HmE;=P-q-V=W;dGfH2QEUdieiv3-;hL zuIcE-vHt}ie!y44{QV-yA%1Q2jh_#gS^K#$EI<5r}!@IbGTpjWE z2ChVs@an)zw3&p4!?d&>8>m4r%mYPnSJ8^f*AZNeYe)yUZ$q1-Ge&c*hUjA!HVN@=Y?9njvud9PuSsui{_j@4TE bm`A*xGaqiiGSUdSRybJ7@XjZl35I?H#25q^ literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedItem.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedItem.class new file mode 100644 index 0000000000000000000000000000000000000000..96ccc83d0162ae41ec7c699dce918a7100a6d7e2 GIT binary patch literal 1474 zcmcIk-A)rx5dKbEx@}pYlz$OLtZ5h<87shCj2#0#6#-D6q0KV`c`-@_|? z1~1f$nt0&@_)x~#w$?T#8lqn8nKN_doB3wW?D_ib^A`YXco2b%*$}RUa6N(>h(~Y} zb0N%oN+OIT79zByJath*T7n|s7DI4Lw{&-#!JkMTGX%1>CK!hDx+MO_H>-xy6RuWVE-tSY4_AsS@t%Wro(#iaS-9TOv2bd- zZ8dAjF-U5Q62tRE-V&~2Qc2CeF-}ZPyWl@Fho7Biovb2^0;&=RF~o4 z-=?A-^fZcL@gjH45T@xVxQ=d>8RioCpM+aR8irp?J$3!S2E|#O8#L%+-9cJaXOhnt zLSCX1+o2xxxctadV3_|s^?j>uW^KcEXyOj{_Za>(s2u?PB?FYc3C>xXctvz-9XjLP zjN5by-gB_?w|9kE^wYyc+3A(?(??TFT9kGQNk+17;S<;g+W0U`YtS=>qlnSo1Cj$q zFiw(T0+Y0Q;513^EHE4p??`rIN4l_q4t5Hc+Sm#a@eyV&=1ax=4FnqKdxNP|EZBhb z7E#)KM5uxA>jomJ_vGnsG8^;?2v1-lJc)RCx|wCX6{($tVqzMXDbGw3#o}~)rAhB9 U#z@9U@5d5G5uuJOVL2H74igf7?f?J) literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBook.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBook.class new file mode 100644 index 0000000000000000000000000000000000000000..114a2617e1012ffb8ec752d8da6deaf6c17858c1 GIT binary patch literal 3342 zcmb_fTWl0n82(PXduF=~y{z5pau*S{^fD9#q2=0zLZK9BOA%D+?Cx|sbUL%lPRmWa z;sw0D0xu8~f-yd*38eueCK^m3DiI@wV2lQ1f)6A{6EP9}&+gLh(ppO7VbA41|NZ~Y ze`e3!JoPbvNAQ*xQ&8(c$b;oxtU#R?E3wLhda+sU!5T3)h+(Z4jaVm!^&V{Sq6y7{ zw?zyaCA4}`giU#P44Wlv@#1kj;lYyQbZX}wBgZA*(93t3%ptJ{p$l-?aX1Eb)44cpWnRWVdErZhXYZpO$p zZiTmL5hwd}U6Mwpj8f0YQ?D6z95rU>3F4eND&q~rOBxDNl9bk@=T!`qqY@tom68?d ziZhIDcGO7cS~Z?5s)SAnhJ>ypK(>;H%~rP^(du-8f{9s0$f!=G$bgKgc!;57AlubD zY~67*vn`y&M2;RM^)gIYWI#q7+sO$EUxp3JqdTs~w1f-?-71Ryqc%0uY0-8%!q4X|>ZUvUt6auT>M; zfDQ>S3DK7sz%Z36pu{XIW@t(*VVTNm8rG|JLR+yjqQxD8rG!@m|9;{4ek$|G_ELyU z;Yf%bkntK`7sDG8-ehPJ2Jh`nVkjI$a0;UgjrZ0L0WAwW4CSNALo(@fGZ})TVHcMp zE1Fau8S$4qhi$zT=`2kA_ud?z2O z%=^5O?lbk<%8`>Gn#6LAUKd?8D4CRt#^CU(h5{{vl6)|0wq%xJ;LTVvvIj%^)HLB# zbB0U#w-f4yfzF)}JJb$khZNndcl6c{Hk~w1=s8GeRG|&Q`a9^OE-8BQXddh&AH%|7 zVjZm!LgUi^i$?nDn@m532kA2~mwxnE(ry~96q@NVfqUjjun%aFgNJG4g2+F@bXv

G-t}5$&hso$W|m}NH(VqZg@!DWM591FSi%2Ubqi2 zUzv~hLRwqy^AzUwBJU9OYFc`F;cd*F=kmKMdNJm0T&?gEzg+ER)!a8W;3nC_cqicQ zL;hhL4Y)~PLE+S+C=R&AVWBIUBpg9S`fShbXM2yJ=roEp2izy&tLDd{eTe%4ZeOvh z5B_Q%;GZL3ocl`B=k97r5DSFS2ZTT-A&^0skfk-8>i;0`| zx!Cc40u(icI;re^s@FlBKp*bM8JtBw%@=S9mub#TmTEU9QK>#fKK~4Ueil>6t5V*N zx%?a!@$*>9zd#fJ5(oHKILN=oF@6#6@^5g0e}_K)El%;vIK!{tEdK%h{Ck||Kj8wu zic9<#T;@OH3crRQ`LDRnuj4QN8!P1ftc3r;Ch{A}60d@UMYu>vnnfjDO5RmrHUX#{ z*D#0vbhuE8-!T{S$X`G6;8Dycpitq{pb)DCL}REX2q`GIiE;@w5*D(*v5a&}SUi60 zgjxwpSmVIp^ZtqPH^@v5nH0!dMrH)CT?F-Z1mPvHw__U@e^T1<0`1#Sj8~EOFV+^U AVgLXD literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterCookedFish.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterCookedFish.class new file mode 100644 index 0000000000000000000000000000000000000000..f856571ebefb2ff07fd044987cd8eeeb7c7e6e11 GIT binary patch literal 1586 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 biR0~R5f0-r%^}jyVGfrNpt7ICJzw)*&)!Zk literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterGuardian.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterGuardian.class new file mode 100644 index 0000000000000000000000000000000000000000..2e02686059bfe3410f4c3edd5d344351abfa98ec GIT binary patch literal 1432 zcmcIk+foxj5IvLICSkcn0Ywp1E(yV`TvRYfS;R|G6;T0GlnE53C`Rm&c0BhKaL&Z!KH>0=}$8F5UF^Bmm z7NnAlA|>UbT+#~eD99+#7$TddZTedb!DOny5Xw1*U>MGuw%Dy#OTsj@=NhFWl#K?iwby8Ppxy7H-bso+rrdFt0mR&8w_$9BUsP z*D{1*`dX=8sgU3XuMt=?t2ImOi{}-Wi_5FUy_Mq1Y~MjQQI=t-EPQ!Z5UyuBl$xs9 zVNmooDTa5+ye)jKN@eLTfA4FaaEY$g=)~4`w+{|@IpMcW@5^Xz1^Ysq07hwzNTafY1nnh|9B>KaBpD`fg;oj9kd$Yk(ZKglBzv*>9&G3odli!% zY@LV%2(yp~q!Ym=LQRBEFquw7nov$KK*mJ0iCD`JPk$!YV2j!~QGxObL&|GRD0`Sz y-e68SY^57-hwP-I;JAkClyFLtL|{5h=QmnJr!ht{LHYoea2avx%@XcLV!r`}Tyh2g literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHanging.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHanging.class new file mode 100644 index 0000000000000000000000000000000000000000..95251492de42c83f039b0233b4ec18437a419eb9 GIT binary patch literal 2219 zcmcIlZBrXn6n-vA?k?$;#uZRhtS>bZLfJxJY)h>)P$V`$g_O2b8!nqoSd!fhn++XC z$6w$VXZ+HB(2t$YI8*%+9Uc7v{v>reo|`OfVzG>)&TMjC?m6c0~J>!%}M2g zibYA6R9uzH4;8E^$Sb(Uz%SUY9b9CHjHFf>qBCC6VmOksU2C!7Y*>C?Y*b03=R8wX zSA}m&IaEf2O}oy}KPv(;XvhXXXrtEw|wm zZQnA3RszQl2ymIqXZOshf{5wV7{(9q`b(A!jM}Q_w#1Gws?>F3CGe^96fat;3Yq|0 zV~9z1f>K-wgjrb-wbtwuTvu>|A->`@eAAk<<&1~B`rFa?aS5T}6$~@<*hK|5HLT$l zgL+liZa|n6Ps2y}n4vctSk9a;916(igh_`QZlgdak1N)&4ng=DHegbUd4eaQ2uni= zNeyLehH65xkqm`34O{ZKf~s6E0$TP0AzQA&fgC(RXz-9!K>fV-zbqU>;z`GsHnwQy z42%CQ6pgEE7G0R_DKn&>z0+Mg#xVA5>+ap6VbPu114@oOy<@4TRWxsFyCJHylmnd} z?H)~~Xc@IlQNLpCE|v1THQJBCPP1@%v(io>^vrHRCS8$2lT?QCEBT%yqf9cK7|9-V zW4oF`7lac))}_Ji8=qbt8W~(FZVA(J1G*=?9@_7pGQBxF9d34uR1o(q$J_b4ddOWN zfOf_EA!OvcS*MgHXZJRKRa6@kZ~EUZ9$v!`eR3FHrteRLess%8dX+eXC?gsh{T}Q) zVtR0t{<&208{`ORZ3DcHVZLxPzCANw94>)u_mew_T znm9ZZYoc$xi6dz}K~Jc8uC3A2x*lqtZ)+$(zeJcw>jPofB(d~Rge_DUx z2@tWQP$bZc@;v>mti9E*3=-6@0u;WEJ}xlGO^osqPV+LR`6iaRjUwN|4zJ)-Ud89! z!B@P72Yee3d4QkzomRuYlxeX%v2uBs1WbAi*_6HIQPW^^M?k^<-LCb DHr6}2 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHealth.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHealth.class new file mode 100644 index 0000000000000000000000000000000000000000..2743b71e937c887dca8d5e06d3f3a203fc5feb20 GIT binary patch literal 2448 zcmcIlNpl-T6#hoGM{QY-op$y;aWLMJiJgSR*o4GNybv!TV;qz~%t#tb6OCq+(a6RD z!oKg@A^ZU@90F9Cr3wxlIr2032^2-~wIm0tl1mCGmA?17`@Pq1>o>pt_2bU~j^Xnd z1~Ao(BbXMLiD4EOTJSh73Ycm!r{D<%^8%L?eKLxqz-56e0#6A%EpSy}LEsqyOCTkX z7RU(L0*eA!ft-LNa7`dD;0hE3JON*zC~#dM5GVY#;ZxMm zM;y-yPibiA?wQxnnD8^yZJTmDd!}4S*}>%MiMqTR$ zJ&Gl)CEF}I89QLY6FDcHw^acW{<2yJwp~;wE$2K+oDHn3DvzkF3KrSsD(i%_MWN6M zS0?V%~9GE32%uuCe33YZs_}$qCam7$eQu!Kh#28)&@byX+Oc>QxjU$MFe1 zjp8#6bN|QdsH^8}>YANq24?=-n;3dsUux*TpV!7R@%>f@l7_DCyQfso-CMk~Zt}4b zeC?s-cuex<^){+O5BFT=JYq+kw^wEt=T?gBh%M{IY6Edn$qD*1=K8A7>rB;Tdic=w zz%KYpG;&V?j!{v%W8+@;jHyw(N7W(g`&rjE$QFE$#C2ICHOv`E%(Is#tWu6E4c*;W z*5zR>tm;srNf* zUspsPChBTa@5C_qcvS!+c$6!;hciT_e27#jH?$YNB8lK1)vk4_4R=&Wk*KNuf(HJ8 z$!`$plMSnA`~gi7+`>?w)Z5dmh~7d6*;S643TgflTl-|Ja`Xk7`fhVkJ&YY(MN8jp z8B%_zCf3gKRaEjdFvTY?5teQkU&! zGAcKkNg<_~Y}aK6F)B9^h1^VRmRpE1xs})=w-MuVJF!*nAa0O5iEVNhv0d&aZj^h7 zQtl;o$bH03azAmiJV4wcJBeH6LE<*~0CBtQBJPk65_igO;x5@k+%0>Fdt@JRuk0u8 ulZS}=eU;RnM7|(21ZG$gF-DKu`bLM*6IzW%^=%%UtBo}RCj%OpfmREen@m8z*XIdc~V7Y0u(TpL;#I@q+~pEAmj zC`nIk%uB~LY|GDMhJhFA;V|4zWi09G6-ub!h&!I{N{0f~7X!z7_Tt=}D5dR6)vj5^ z(cX=jGcbb&9T_fEstf}grMKriQ7F%fYEaWy&aOEHIc=z_?`g`pp%?@A#G;5JiOmdc zQ99(bzs{~ zyOK9#;Hy1XmZtPeaplT`+1HaL3utwf!@WE!f9boBpx9)Bs{1pF# z59&ird?4{b6a7)fGo?rycp;MP&Y3gkeCK>~=FI&5^X&-0BAzCZz=(l6NsMAl4R;f` zhxHE!-^; zI7)9VYSFF}G7P>Hk;wVpz6>H6Si;+3FxNa!202%Rp(K}rW&2egR+g6E^8-I{%d+f5 zyi~7LNQkni5s*98n#((4g~hqz+(L0QF3&zJV39Wkt5ZXSl-j!H1hT;wpR33o;KS{~-N3x_qT>u}mS z<-8dM4)xGl<}E{l+UQtkm^jBNa~5~9|9a%Oym>b$fwqy)7t~#8rfD-#tG1QvBvnu3 zTmAvv5)l&kByl_J+{B6SlY|oNaH~Yo^o(;xe(8I!zq*o?JKeZugy)@$_8OiRc zuV9~P(uF=6<7&}3LO;!wD>+~QS4c8k#So1OoF%Dj+F)$PY z`2(ZVsjdN|f!GHO(UiUhv@hsxAl`sJ{fS&+O-g-=x$y%%#!q@8e>KAoABSj#r(n2_ g8ayp*)3tbX#F#rGn literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMaterialId.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMaterialId.class new file mode 100644 index 0000000000000000000000000000000000000000..4a6daf619ccbda05231e7e36914e4f86dbdf4bc6 GIT binary patch literal 13795 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 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMobSpawner.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMobSpawner.class new file mode 100644 index 0000000000000000000000000000000000000000..ac0c7ac793e6a5c4201ab19d3351c8f58c0d8f64 GIT binary patch literal 2400 zcmcIlT~ixX7=BJRo86>ah-;x@MQdBzga9iaY70m!DV4P0qmW`nY1|}BSd#3fy9*t9 zTmOKU?Ona87mkB7PMqn5KfwRtj2AlUs53Iv;(Inhh%h6Jda>uc=bYz#-p_OP>!**u z0x*b51jlh+#swKe5e#D_f;TZL<04;NlJORw$M|Ma#$~=3=ff2~ye(sbHm;u;^) zGA3nA$(WXKUBaw{Ifl@PX_?+AgAj|)GX#@%!C+`jo0c)PTFDtsM$eULM@`##y*#fw zCSNx;gWj^~G916GdwSBg)(popoJl)3SJm%WhQpwwESi&L-E|EDE~N8zMRQB%FWlDd z*iN}%6iiRct(HnO=>@$?>Y7=pmbE5EH`|x(8_3S~XZz1I9qgDIW@srI9zUHo9M`lh zKcWWiom(X;-TDs#O?{9}dpIC`2{A zqOa*%S+|PXoadNUkz8xFa-OFbDR`f`kD>Rl+<&7O*hAV+_D%XIpXIt^-+0 z6P6qm@|7yX(K%1gmnQY9UuM5qZb+Dy@D6d$*{e?8xMK3A=xnOSt}^xVBq->>^Q5s; zC5C`mkZ?o6O}tBt3KsAlgFJ3|rnjCdD0m->3}L^2IJbgZ$SU{%I{7wZ78T@>S5SbV zUdQAPd)~H%dMPTSYOp`acSnpSc*g+V0$55&0(rv4qjqUCI_}(o_zHxh% zYQ@mDTce(!;rIeQ8_T+T%~+pas#mUkH>`1~QXF@LtZ!dehOvEMhrYv->5f;b-n##M zkcqIn6X3ah4D5}MKcfO^F^ueo|Hs^p>8>%%NkWcMvDc_`o6^*Xp93Tczg~um`&ddH zEcV9D54z@EGSwG5pxSoY>Cw3KZ#x<%(M~@)hUe(7C(uXl2CYtzq|wZ17Q4O#`<#RT zUZ63=H^pzzNwQK0;6=PlD~3}zO(R$Cp_wZS(bA_h?NKVLJS7nb8BqP9v z8c3)@4Z#}32M`k*2{jazYmn}vk3>3{OsKRDPxYumcMXyIkkuoP5F}Zllb#xm`nZ;a z+8Pb}ii=!~)DWE%Mmq`j%*VLe-C2V=6zmA9&u-I`e2j>P#12sv_<`?*LQ-3YNVN5> zmO8BELxDZo`XaHx!}U`%i({0c@6aNCkEr+qPKZC^l=u_k;?Ecne?e0G6)EvIWW-G@ zice4!e}^SL#a(d=_d*OGg#vgG67Vn-#3ywASt#u1Y!))5_#DpC7eE{*5u;JSJ<44d zNg^x^Awg0QSxlpw${=77*U?MW4Dg&b^3A1J2}fN=yAzP2Tf`ZZ&@W*?!XS+Z)Wt0V uG#?1tn88i7{(&|LudyeX*d+S_yiV`{-XPxqm85pe;3Y(;zh;mLh5rOVAa#fU literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterPotionId.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterPotionId.class new file mode 100644 index 0000000000000000000000000000000000000000..213f0f4e58d6cc838ec2a4db6688de94f8646348 GIT binary patch literal 4550 zcmcJRdvIJ;9ml`t-t)_zq}z0RO8QP)`c9K}oAllEnY5*8(`VAq2W`07+$7s3WCZ@5m2eWd+%v>lXS-EpfkJs zz31`!ea`Q9e)pVx>cdCA17IocE5UN?Q)p4RxCHxgpadER6%P50OB4?KdPJes*Gr4B z430vZ-$?jB?Fz219T9XYbSWeijw*C3q!fA-(h3=cUWH={S%sW}r_iU+uP~r+nZj{} z%N4FrxKiONg%b)_E1XogM&Vk8>lCh6_?W`S6+WSGgTjpw+!Vph5qwG@(wp&;nRHHI z+@Z#!PQMdRIqA-Llb21VJ8K1s)+EzOZ=HZWzoJDz)@RyXfiaEAw7avfr_IeaJ8dcM z(T$melWK9YNxyA6rPq~Y&t;n&&#BL(``xVPW_Jg`hIWByLptqd>r+lH=km1ujfqT8 zJlDN))v@?MCYx$^+ml|rt*^VA#c6kX**Ko;=}pCl_{+6cw^lD{-CNUIGkeIuSrA82 z+Ua`!Sc{v@akN1+4IF$TT$I3(`HgAUi}!F?iLBG%#dB_!mmBXlzT-RVnwy=@`b&j%k#SCfU$Pzuh0;8KeC(*sb z=?!)w*za4oyad#mM9S=FNmHgTn{c-z{rxK+lDdMNF7k^aiq+sW#s>4VIxHIjE7=~w zEm7Qx+oJdkZs!GXG*R4v&vNl>a(bLjH;T{U^V|wIB#Jw6DvFg@#dVZ-INi$_#`v3s@=F=?z!~eO*qLt(adBLXf}Kwyf*$OE+w7$+W+&wqz>l z9Ul^iGtfQYWcgJr*a$XHbaO!ztjo)0(w&^2!kkVXF1OlCna zoF1Q;&(cV*o3no4<`<- zl!8Ub6cl9OZ7@s2S3ja$hOe@)W+J#(poNd9|HJ7#vK|k(3BNggdx^e926ME zUhB=dFHl!FD}REq$K}5Tp+;;c)u8!v8z5G6mKL@tKUtMu7AM?C( zOd1)o{|CWlD}goVn*U!@UgzZ8THlHC(P0$lT3(YsXTwJ=5zOE}V#^`0g1?jf`-uO{ zN&fOx$31KKDb6ZbX~Dw~5AuVBwftM;cgn}Gj-R991gu9Lw*>03iGO|Lg{;1@9qYKC zrO@>80#kd?bThVureYy%5ZfHpR;9L2L!Jhm!r@9?bQ+Nzm0F!f@wzHq661$acVX2- zh?d8$K2ft;a_1!Z1e6~ARnR21D`lgq(->1eb^}iE_g;)*mpaBH<)=`>zS#fR$_M;~ z2Eo;ENRU53sr(_zPv*?n~1<@?!6<4DQ z7hx-Bu?$UUz&4J0DjKn!zqTKbiPeAF!K3`5bMJb{GwgyQ*cHKU{)hT$l1zQC6vUFJ(fkM~9C z3BJUN^u$0TA`qn~1zM~p2U?=11UgDj4K%9D10AiW1zM`72RbG+kLejfb8JYC=@18) zTh9*KbM%}*=NkIF(0sn3SLnIH@B%}x)boONm7X8yLPK9<=<(2eaVXUWUSr@(41B49 zFEjAv2EHORTWR2{41BeL*Bba517B<4>kNE-Xud&L1Z&%<7X(_TD+8_9Re^5O3j^J3 z62C<+3fdQi=38|$I#P;o(au+Lpf&PSp&}*xM$#f2HtPr1EJYv27cVYFE{Wj z4E#z1zskT*82Htq$v>Zke}q{jxR#HwM^P-FM@;@26Xb6&P5u^hbIlz+x;@-H|g|BCzM8~D0>6A#L_ z@NM}v9+&UnN%=SYLjE1Ul<(q2`47A*-@}{oeY__>z!~{Z5t08AW8}ZZ1o@$uF3*U0 z1Q918R*)sukuA266g!DT3l)hY6cHVyM4F04Kb459Xq32~qT*&6E$*OFaSx3VU!j<| zpT>%Bkrt2AIPrbDKs-%l;#nFmo~H@oWtu2nr%B=+nk+t`DV9Z3tr9A?G)=Q6({yVl z&9D~Gg;ovCv{un9Ya`9J8fcEShvr%bXrATJd@D&6)-hUOT}GAGNvg7LpoP}0w8*-X z;?}*i*!mh(TMtl;^)M~5zDrB3Cuo`Vb6RdaM=PusXr=WEt+L*r)z-UIYkf#->>^rg zm(n_WJgv8<(FS`iZL}9roxP0e?X|SY-b|bA9kj*XM;F&3vS5TvU z9qq7hqMi2bw9CGmcH3X3J@z+ful*1;*^f}O{XN=eKSeF}Gjy^2E81_rLcif1?m6do?)i7`{`K*XKLOmvY6AV3af{=&QrzLVtLXO}_Y}RamIoTpF+h52gRY4Qe7uIi*bMZ01xqrx=E!Oi4x#W*KJA>LO-UJqAX_GID$3P?#0rl+E?fx1BQO zcz!(;*8Ym{q84a)q~S3`V%@FzmV9QbRt49L)-IYsUUpcJ))LSd2~F(k2HFX z?&p0q-S{O3K6`qt5ujx!s*Wtck4 zY%=uFwEqVkpEx-ysgokAxjd+e3JuplJEDgb-JmC(&oj85jGUaT0Q80Js2|KEBpia=(RlSiN0Zd^x_-ebD7 z^f<@pqf17+0pd)ejOe+^_h7#h(}h7=yOoe{<1+Dj!vI(C73~QRUNMeES;3>E9 zg70CAJ5jKc6wn;Ts9N7fRoZTbO+jLWWb{~L4L2}KiH?!?e#AZ?tzrBFhBVy#hXh@i Xi0Y8SRiXy%lgMBQ3F0$&*xmCl;n(LS literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterRiding.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterRiding.class new file mode 100644 index 0000000000000000000000000000000000000000..94c5c8e9b2c82f8e175212ee97e5e96967e8d4d2 GIT binary patch literal 1936 zcmcIl>uwWA6#gbQv&Pvti6IFgAq7fX$9A&h!mUoZ#1tvQ2^Dcu!4IslJ#jX%cg^l5 z2ws3^0Er(|E%ZkOL8wLoi3jM5^et%5tQRMiA~jZ9S$k%7=A83==eGXi)BBGAX7PO# zF(e`wk0Oaw6g@~QF`;2H3XX&lMg(Wo^^_9RO3Y|Dr{TPY3k-bDv`p_ZLntx6!Vu2d zWy#Q+GcCEaSu08>FN#$>#;-&k>1KX*VW!dzM;^xK%Eut*yWNMhTdevz2<`$+3Q!|Cz z(}n3XZ5K_L3`49UJ$17p9oMuiKavFot<)sMa4(Uwq-WG9q>>|6J;Rj_Q8l&#&&JYx zJ})X+yH>Y1t#W3(Gj+L1%y(u5wTFpPKQ(XoVxn0i7o82^`q0Ke(@$UGL-bHP(_5T&2CYn;Cf|X*p-mT#kmTx+KgChn>rDj=;26Cz4C6RS zWjsl%G7k6S@iwh{ZJ+J24YzDZFdEoCLWq9ASSsGt7i}Q)1V@vp2EvQURJwsf>Dqc&{rndU@n12_UtpB~<|CaXy?#V+0%OF3{05k6_XRzSl0Z!9 zZiFNaZNOul?80<2_yPRRJ7`N2L?ZH2I(~Sff#_~V;!2BeBf?)H#$RKA@A$aMrgaN# z5T|`K@)&T5Q0l+L86Stf7y<5-p4OYt|*z34A`S_RxpV@zH1x6t_S=;4i4kYv&V h>kYuPR^VOu+V}7chG>nGuO9mE9YmC@W^s`p{u=~8<5mCw literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSaddle.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSaddle.class new file mode 100644 index 0000000000000000000000000000000000000000..865101fd6e5027bd45d889fc9ff4c55bb14ad291 GIT binary patch literal 1777 zcmcIl?QRoC6g^`nyPM4d=@KZk(9%F5iA}cofFwAj!441;e?aV7DnE$E_TX&d-8H-8 zRCyHo4E<3gWF#u}0s2ans@}03utlmWD*W)=nY-uQd+wbN|M~aZKL9MDV&WWT4I~UC zO_;c8Vh)ah@6=-6z=E=iI+m0r+%08q8(3C$#lWhvchrzl!%MbD?z$1f*$pmvCh!kLC`DM} z^}1qMS>G37rpcp75U7%?1)dY_udKdseh$KBUDRFaRNMReWO$voi0ZgrtLY3yi+1LB z<`;Li7j_n|4SndPNim#m2&ukQL>Re&->oFepx1hW7@ke%d?6i=N~(qYxpX2Cl2qrQ zAK59S%Vplk1YRp>`}Ne!$>7v2zbYkfP<`D1^9*w*4H2(-ErwGi$!q(0-s<<)ECubb zCLXw|pO=TqALz^69zWm~KF0-y@%z4X<>6)!Mns9Zbqi@^bZl6-j|U89uWeZ=JPQx8 zNe7_kv5>_hhU7^)#W3-%sdu98wp-Xjj$t%Ios<^xC{TtC?(v4OP{d;kPq1yFgtCqw z8OopHOpq+q5vR%hhEuHWiJD|6eB4a5S3}#uFh<9)BtzG4FkGL`y;sn4(y98uH6-+i ztBDtF-lPk2ZZJr%jMU6ix>vhA+7gGw=jFo|?eY0RSU*=*;Y<>g4uYoObSH*_9VsHv zSoB`?jbkExC|bP|I z4oJ$eB@$r$|L#1lV3OWnDuf>6IQ{6R(dr`29I}k;=LJ1Tow6v6@DKY&43PlJt2&p2p5(!1(K(ukTi5tgG?MjJL;SwwSn>fwG@aRHh~?d?U>GY{j@WKDE5a-BicOYe!8N(P z%RMX5Lt{+VEuUfX5tlsgI)}oO!YkI>c0+g!`j+DeFK=_-7v%M#V7g7iZ>--vFpgZ$ zu8OK9jY_-GAi=A=MOedXwrpb{oL^opFRzxLt&~^h2M)qK8w{g0A%mk`;rW*9bZgmS zP|O}BhF9r=Bc#!!qD+tPNy8T&ku?s((8l&=sl;n}x7l*rPIV)5I(JHFHd_q2)51oI zlADdEycPCSE4ppZ6pyW-_+*WXh;rV~L5r*-Ap<#2UX6#hh%@Ap$v@=LDl0%E1!9LL@f-zd- zfl-whr@h{Dzyu~qql%HDH2~*G2H@C4H2r~OKlZ2(8~cephw~w}PDCPvnM+2p$!G_$ z4u;+#l}*OS%?_0J7!I~t2Ws{sxkbCQMg#WhYfPzcFsr`prbzX|gefQ>rf`9hT_Hd!r7*kA>CRh_`dZAG=EF;~ryF+Ie^i_NZ zO=_amc;N&1P{x0OR?w?Pz1aQdKYagr=KGJY-vF#(Er|qXOm82%l+1!y9fNW(oRD* z?10xhtrii{5N-0oZMW_45x0JAxwgDod%99vnHy337H^#)-IPISvMaT3E3a4E7K35+ zQ)GCVuXr-xE){8M@hafH)Ra8$4npwljh!9QEGxIII$mSFa5{4eXt`~M(rIDi)j(LS z$D%#xZ?dX7+LD`gIDy%bs)yQ9+814s!WpC(rcP?Q=lAEp5V0EuiYY8&$v`Ouj@t}l zW#uTH!ZKD2tTMd#uR~#&43p%J@S6NdeP3Du!}h-o$uK_BA%?}%44EN8Yf}xh?KK(Z z^Oau-_l2|te~3ovI>yH3K}R^W>C?kb`c4?E`6uN~E|F$!9$xV6y z7?SiFMCqgDAa0yaoG2qYw(uG3105nr(?1>x&G(p~b7)Ein8aD43|UOmKLnSEhPv2P zbm<+@VeH`$Hg#9v8^(#U6@fNqwo8&I~d{GsK&i#}w6{B)Sk!`~>IpRzd&( literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterShulkerBoxItem.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterShulkerBoxItem.class new file mode 100644 index 0000000000000000000000000000000000000000..cc47a10e71993cc5ee9e3b2fb1ad45c77a9c58ee GIT binary patch literal 2726 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 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSignText.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSignText.class new file mode 100644 index 0000000000000000000000000000000000000000..eca776466a9d32b36050e43d8106436d9c4b1090 GIT binary patch literal 3133 zcmcIm+fNi%82=qum_6GOaV;vK#S1D6tRqNUWvv(18;WRMq>2`t-90V?voq_=EO@E* zW@7r{la0|dwQqf}54BCel*BZtNt6ChZTg+r1!slQklIc5d~?40`EKX@@z*ae0QBI? z2)3XvjAR%`A~=d;5gf;fF#03djFVxU3S%IQ(_suoa0X{3^+UOwQ;>>aHHJ9xomVg% z!AH0d#zh4q5nRG$xqK{_QK@!J!IcP_(5FC;U?ckECM}nY0-@llf*eD`5#7_1wlyUj zPdF(fXAOz#9)sF%S;9%0y6Xy;f$0qE1~PVD%h`6$6k5);E$uih35MGJhGlpM7^>T1 z!wjLMofQnL2MkLL7V~N04C!f;Fwp@!qnpFJW5|6O8S=&rGH}6H?oRIAcTJnN9WyJk zhNq>AlamDWtX?4RG$UUywF-ybv97VMJ!9v($GTf92=gZ)_v&)OleA&sxQ1={ZuT=M znbN5lM%xA~;c0pDH{(&PQhKBT9(#{v`qLod=R>n>SGx-9;u9b?d zN_l!_^0Zzkhbp;3KL;lCDP1#lE2pJA$FOnW{d0@ zSp^d+CSj6h6?qV{M%H7Oirsj(yy-5(J!RNK3ap|@GPa5WuBmX~s_>vOXv-%yIj(zt zS}kFD(vWnhsA4;IFzjAlwqFYO>8@B%pkPXhPBVaED+RcsSx!>3oYfsy9KD_q1&=CG z!F9=hQ+iFycHC0&32rkqzb-2qt*>ZMS2)xvlKSR5rImtw2cN3=44*6bf?@dovBOaR zsxC`~#4z|~Z85B>sJjZArCwm@Tt2^*P0zq-jLeJfXj|MbvBfCr9&xRxo77+pL5Xtv z#Hep}F7L#7&oGm=X;a!+`ZX={Jxy9_Gvm5*n3^=y)*nmK-V|2O8~+CZ8UnkPH!Dl~ zh@dfO=%#T~7TsXm($jzOp#vEI`bdlfBU3&)!@=b}SlnH$(y3IyrMlM<$AU4QkIugg z-Nkn3#vny2^^PuuS5;lMO*P}bs+pZjc(+(aPUy9c$QdqOctbY|;&AEiW9SdcJL0NI zQ(2Q7iGY^*%33m6TI5v`qtLLgiMyaXZyI)0R~Oq#5R5k?R?O;yRM|WY?rK{8+*udkFSBX6Pa$ak}K>fLQ)-Gc65>-gRD0c zeJf7xJjOTi=TINx>o_^Ms($Nth{lOf7s~qECy12@w<-y@pP+sYt1rf9QQsT-9{NvM z6OTqi&#|^Q)EN35b&?u=yG*X>t?`j$Yn@~d?AHhO%|Vqx4IQ10pc8t5vyi+cp`;{hHLEQM|q>nU{SP|H)`{5%@@FivrL#_|zl`6U?qGCY0-(|i;+ zcp7(j7I%3L_qf1Ud;<5mi3i-qL!QSY?%-SQ;whiT48Mur_$@#DJ${kBTnPV5yyu6X zVvP5(m!e;b7uZK%)!>*zFA|gknVc4=f1+E#egz+FP@C!He1M%^Sk^=k#=(W!?Ij`k zYnnsT#aT2*qjT6uADd?I&J0?9#u{1B%&(X_G6lW`Yxw~>@)mO85Yeh|7_9`ilBUhb XVjJW;UH-y^%VNBi(_=o08{mHfT+=*@ literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSkeleton.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSkeleton.class new file mode 100644 index 0000000000000000000000000000000000000000..bdbbd43b8634ff524aecdb6b523f9272344da345 GIT binary patch literal 1549 zcmcIkSx*yD6#j0v+m>OgA}&->5L%XwEGnCb6irA9CPL8oKyy32mZ7thnJI>!;u~+i z_@FP4nCK7iCz)tG(?#0g3sE0t&OPUz?=0Uv_kR2N`73}~JdL9hBTt_Z%ue2Yg>oX@uag=mWK3fi$PhpEa_wo;kuICUgb2~RNeC2 z{DJz`c8sDd>YiGtmdhkWQB(-5>So1I+v2(Tsr=MT{>5~Ddbn+)nP`!rt0X;tZ$~<= z?x&`1))}}~FN$F|m9wO$n$(u&h&P_fYYjX)0L36NWGq zCXN)WBFnMHu=9V8l%eO0i|2)Xsd)^W|27wK+s0j6&N}}L6Bn5ph8WFZ6FQPQf1c^{ zCc1+1pehXi9fiNF$?-(w1bjIe zIz|`mC88&Yy+=IC;d|)k`xxM5jB*1L+@yE5 zf(7o@Y8s=w{TRXkk~K1x8r4xPxQSa-A3e$##BJ*54rS;>@COCL5L3P*OvYg{25=Ww TNG52dUWG?)s~8M literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSpawnEgg.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSpawnEgg.class new file mode 100644 index 0000000000000000000000000000000000000000..1e45a0d6601adae58a419373cb1377f7f07ca0f4 GIT binary patch literal 3822 zcmcJRX?PSx8pr>Yq%t+hgoJ{CAPVlXLI^MrkSoYBAqiP>EfW(Kl+ZKNnQ79~J@oVt z!mi?a;f*(f2i|y~TpAPwym8%wz1iE3e)OaJN%pOp1j6w=`|#{;o}_qe_(zX$jn~kt-ILUC-_bew_%TT=7ax8xdL*dk_PLi#26DC7>v*nnrxpd6* zI*gc2E3(;*8+NDRS!zDGSmdWHvRt{s@Qpgx*=%~g=|wX}pHrVqGK88O$MouKBbzlz zY)y0AO^36+3l?q)_qm>(FcX#^j^%oL2}Z)mkaE~cXYBBK_OjixyJyeoUR~2&Gx@w1 zLmN>PBa)`C-gTN@)^Z&kO%p>Po_C62{nTd1^uuWiEAAORemHA-LP{$D?z41_!WK~!YTZQcBkM%_$_|N5Uh86%kQT=l7}mdw2?GJ_&xp*!XNRc5W27? zgwyzQ2!Fv}L--s1&QNh-OHvCq`DU7duW4`dVq~-<<++0m6>K(*Y-*L``V?HdVbOLD z?ZuaSBtlD3$L)(5woStZ%QN%CvS^x?&dnzs?I zWVx4iJ*vOjqbTAUBvjF&THWyc)mFmHAK|j0rMi@vC6V%>c|*=~jJS$pXr-gIgZ3Gk zt#rvdZV4Qx}t4Y0D=AqA_Q93388Oh~}$6 z;^dBUGDR`btWLFFpe|)mMM;iFH{~oeUQBgpi!xW-w$-#%AD4An zwoNC+YjkbZ_vEKKL@Qk{OAZvTHexZ0#Ke#owWfBk&g;+mh8@5^7&_^8`9EB&=N-?s z*hcC~hSvY>UX+0IZX<^2mvd25x#;T8f6W-KoqF*NTy^mhrPbV&Gi)k-<#3IBh_zL8 z`<0Sa>S=vtGem|<4SqT=`wJnIqw3neVAmmgbd!gu-&dLaZ9N_R87lsmOKjVuybET} z#XRK_LKlauzU_si#jyBN^8YdA5hH8XDkDN|osZ&D?nRZ%vj4V4Fp2&jr1&5i#&##XdKE5U_A_)F~kt3r&69lRLX@F z);_{;RdbkX;aSxL%)Bb&D5On*ge<6*g##!W0N;hKYFRu$7v6L!2(8sJIDnFQMKfe! z1uc~B#aOs!*3#Aaq43(m=iA>N> z!8Icpj-lc(LKJL~92q5WDHSRLa+Ic!qcwxFQnN&k(JYl?HAC_W%`!PobA%kPSuU^C ztdJ8lN6M=-rMy~ml$@wJT29iel-FpEk>ArCE5EOKg`BK8PX0i1yu4QPYB@!-N>0_B zCaW~7BzT()T@WV@y*f26rZ zu2vk0FJv^Tjww_9%*LRe`gsF_{5DkZ+cB2kfr3FG3?=wV=sRK`}s~B;ZNcOoy(JaH%{@V zaGF1julO_gnm>zg_#S-ApTimcJPYs_SUG=@jpZ+~iTq_Yg}=hWd@q~NUu8@AYpjvK z&f54Jtc&ks-TY0KS+b>JkrQ9?K2N&KQX_-|61``7>g literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTileEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTileEntity.class new file mode 100644 index 0000000000000000000000000000000000000000..314ad9cfb7a5f4b35db770b66ad3f8a3c0fd39cf GIT binary patch literal 2989 zcmcImX>b%p6#hC_cb4TEjtB@uMMxlIO#lrfBIE)z36aErsI0xSlg%WvGt10umWcO> zCti4;{Ism{szR|Wi(gt;{;;%)AKr@hiT~B|&F&;KODwA>wNgpX_w~E_z1Oev&Y!Qp z31Br2Mz9u_RH6w30^1|lflH@gCobc-+yhrcunTd4D+Q#-Cj?Z1q<|(cD3B5u63_*P z1x5r6fwX`rU`7j({tW6&MxB3G5LV6SzuXufWv;*9crIaGk*Q0yhZUC~%X& z%>uUw+$wOJz&?T71?~{IQ{XOvy9MsyxR>KTj{6yyWSHJHEJtN5>*_|VTV|RWD*N=5 zDc!8CF{~-xZ7D!QnyFZyYwKpJc`~z}Y*e)9rtYq1D6Od-U?^*|l4Naqmu_l3*>pm) z`(?r)M(MItX$(kP_pncvxkI|cP}MG7*=Cuen(dN;ZfG5*tGie&9E}8b zcBxi6=8QD0-5twWwvp75x*JPmM@DFoNtq$_n4ZoUu_B93ydmDOD!#2T-ngV_BXC70 znU>OAZ+Aem9o;hXC)&cm)k0tlyK1^j&5fn$XsRs--I$}<6mo3Tw;tE@oFY*>00DE6d!fl1kI^IUE87qgglTynrz1thNX@$ zMB2OBHCI#fb`}I~l5)(@Q$ub%IkC&zZ7Y-Ujyf|WH_k;nOm#?_u76MF2O?Tw!#kE+ zxLJ`7Gr38+T29i1nG=>w##7_GCqx&iaNJ@c&5rwNsO&VXoM!i0l%!A=2Jr3@`bpJ~ga#V{zV-it|NHezbI&C(enM0c&mcb$JyeVQJU(oB{@Z3=t! z;|h8Gr{FjI+XAAR{!v*AhIRBi-<#XCo=^YClwdu|Xr*yZ%trc((aLBoU;ZlCOL>u2 z`di_V{3zP!J6aGxJ2nww*o-ao*Hf;i)l)8;S#sogT1yb>@dnpa0C_Ib#Ea;RNW!)6)%!VY2K{jMb6)Y!r#YS{s9*9V|f?V1v9=2 zGKem8lM@9~(SxlNR4>^OV84?JE~c+-d#NLd_!YUPXooT;1@fF;V= z0a&Um3qXxh8-V4?iU8CpD+5rk!~$@R(hz_~WmN!HD{BI9u5w-hc&)|D` z;2&ZZ{|MFmW31$#U>*MyoA_tw=buCJFJSU7v6mmmKK>OB@UL-@e}fnJw|Ikphok&^ z9OFOWIR6nR_)qwQ|I8x%7goi8WlQ)8*1&(GI`)yz67-{!R)xNrupb?WP?zt=0~M8j E0kQ`-+yDRo literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTotem.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTotem.class new file mode 100644 index 0000000000000000000000000000000000000000..812e91062fa3b88beab4910dcbcf9b89acb8b8a9 GIT binary patch literal 1318 zcmcIkTW=CU6#fP%yU;Cd(V|xCwYE?yV=oVCjWJ@HG(k+H_Q6ESuuO5wUg++C@u&D7 ze9)Jg_}~xl#l#0q{4vI}u(n{I8a11pbLO1$o!gw5&p$tY0#Or4ihh(0hD=MUP_ZNZ!1COF9a{{VIY@`$ zMZV%n#T_ch^u?~?f%GX+-isXb>VxfV(JFgR$LqSyjl#*yDWK_e7)mFFP1KYy+mA#i z>Sem-b$wHAT4A^6Mrs{uLTOL*gn@AwbV!Fa-BE*{$E>D?qJd@H&`>hKag$;853{YRBE&jN%Cr!mr{kMS_CPrGtuzZr!W=PTe)Ra%n zU|7gkjuIXSX&jD;M(X;FP0IbQuxZd|hMf$m-Y7hyK*3R<#bKK$(D69oeZ2p-?V{_h z(^J5ZrgtGuKaCFUCWzxi8PTz&4`A2@ef_fmJaHT)F+ zgAe+G#s`0ZKgxKftw19_5J`6DoHKL2?_B2W{`~d*2Y_Ad#xR0~5iG`V7x&b%6vKTy zP})Ns%Q{wcJYvwES*{g6XNaUT6^3Zet4oH7g5}C$+o?&vENV9GBnzG??27O$W%oCu z;jtAkOzw$L&)FgfB)OCerswdW`Q+(){=xI@x~y9vueF;^ z5~40z1mu>}viSg4P~EC-?Nkr8tJ|r80~I98Fy4@%+OJ4IuspY0MV>)7d&w}oOBY-j za)-(>eQ^}>K>Cy>@AP?j@nyLz8adBtd2P3z&0No&0-8>XVe`7McqtTS^NncrI~gl^ zZQqoyEY<79fl@E^VDm(Dgn<~w=%!Q)bYu*yV$HxhHgs$n;CO6c3)?z&7!Gc}=?n># z1h<9T;QO@`X@(5Nn~lQ|ALszX`gJamhVNJeujT3fQTen*{hUr0E^;n~zU4Nu`OI5} zQ5v6~&9HKXQ|50R&0LqO9a=W;je6|J_nbd8sejX)LuhcBU|7DwwHNThQ+<;!{qsF%#gCFqYoosbZ+}xs literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterVBO.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterVBO.class new file mode 100644 index 0000000000000000000000000000000000000000..4aa5e2312610deef045baae4b327a76ba36d33a1 GIT binary patch literal 1102 zcmb_bTW=CU6#fPl7FK#gt=DSRYN<6$T7A%98p9fsCWJ;I`zRT9N8GX(oSnr#<%7Ox z;)6fHf8>ktERYKEiP(pk@0>H|JC`{#KYxG!0pJOCEfjIBgzF{Tuy7MwCT^S9HgSic z_}q_teZ-Kj?KupF9ea{tt>s6uorZm>x}qPDrP_*J5jaBmnLaZb`n{hptiKdm*l{$L zN=xN5PZ%o4Q6!Zeh$NBZ(P_DH$dlpIXCL^-SOuQ+e9imma7Z9LF(MxK!%@H&LM6R} z-ofMEo5SAW&cXrZXfUh}q|VHaREZx)lOB#4Om|ue!`oUblA4FqjH|>u%@e7pNIss0 zW)@^ zG+@}Rwf+`7H8%dWWbgaM|8{|G6zDh6E2FQKr$yr-%_4~tGQz^cZ(v_Y$l(I*nKR4= zDkN8?4p_lDX$%{v(w>p)gc;e`V81>Q&U26ExW*axA}-CiO)4Zu9BaRttLDGL*#CSM s!OBj|CQ7C~iLyEMoJAoHE@PA8!YZAcgm;VOKRKrxX8-^I literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombie.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombie.class new file mode 100644 index 0000000000000000000000000000000000000000..7b70c16b6062baeb32a5c346aa2904a8a76c0a5d GIT binary patch literal 1955 zcmcIkT~ixX7=BI&IU!wW*g~;{s4cCS6+CbzGpY7iNg(}UhH|#dG~ogpZAc_g)@J&lA>2}qrEi%NGOxyHV7<$r~3PUvSR0YGuqG^lGMr~iXWqscw zjaqaJ-KyxWDbFos)PG`n443ZdzMgmNW8wP3-F0gFCRr#2+ZJx#(mhWQs8TeXn&utN z-+iWi=D1c>R83#oZyX(w(5rf#Of|Dsx3n&A-rmgK%-mjSc5gP-^&<>J6$~5-U;e2G z*E1bEsDvu!Mwk%8r|F_Ce62<$8LocdYo2f^RqeRtS=(GIm-WNEQ>!}-ySkV;ADo(N z(nleCj9Q%`cV6@U9bY$&9_aO;s{v^n#4M4KE@a4Ue95p{Bqes7hHHp*Q&KX~)sK!w z`WsbCA+42gnQF)d3!6t02~P$Er;FTbb@1v@Ac^KHbo z>l_GA_E^D(s3=Gw$1oZUm8IK zNpEg1eRN4kGe$d&B$L|dQ?T!76TvvGF{$K3n4rB90`MxX(TQOS*J+i;Ig-*iI>>(e zhGeJhNQZ6orELnYwQPSy529qVr$(}BPZQB5dQVWws<9^c2?|*?o-~^1`yBI;<*b?r z4ku8jY2Ur`4Y+L?=g@hyNgmwhT}~n14o0|Zz-IH1uUbV0?N{6sUYw% zjPP+x@d>2(RcQPg7I+HFdA9pT+ninx;J}5Spguaqr5`XLnPnZ!sswq1bP>#8lB7Hj QVI5bIpkZ0Z`?0>i0KO#7bpQYW literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombieType.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombieType.class new file mode 100644 index 0000000000000000000000000000000000000000..8e281651076ec68c1c4c1f5a4565d31a48637498 GIT binary patch literal 1618 zcmcIlTTc^F5dKbEdP-StMZ^mTD$1q63U~nl1&RoqUmu`b>2mfbCe#0QOu zZ)##(4LS0M26}h(??V z;A{XrLG+?8h<=0v7;qPZ0SviP4d9$BhXWXK$4Y%@nF zWzjIC714!lOLAO|Ce5sBXU4|Y)kmhKr({ZV)I>g$At6#CM{rfk=5)0xq8%TO50A$0 zjKoK}t3K?enqX*1OUM1XA}w1pjUuB(2A(Vx#&EwkYDh=T61Aiy9yqEkEh<^vC`VV9 zW@9mtj+oh;nKx1seFt-AU>ZG?(wofY7={iCuU~dVGILYp%H0hvn|UiK=QX$g9aY3D zIx@5-HiUv^glIEM4Po$TDUNXkmodRHsbC7U!@=ElDY%MhYFWv$qUpLwOH08FX36ii zWj>I$+e8Hs%+XXV@ijG+QItedS2*sDq1Uplvq#nt$~ZZR)C zG`_TIAx$O8NY?a!2Kz*c2Z!kGca3}#t)wd@2OP#xS}`2MaeBMpA(AfG*X-H;K(Z41 zxB~0@jcrFq8T$>sVkzm6Cmiw?;47f!9ah63e*t`|{XK=FyS4Q5m-RuCe?Bu?=%fIl zKmoPkP_W&XDxhu)b*@b*+9+Us_#;8RMQZ&B61692;7`%YpJAFmM})t?4gL}_{t9>b zYsC2*NdC4+p^I>>xQ!F&B!WP?Ovcr^aFXbpBCCR$A9Th&E&Mxb$nP}SJm|&|k|EL> P=-;D_GB=SN^Vj|YEaRCN literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspector.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspector.class new file mode 100644 index 0000000000000000000000000000000000000000..8f814840081fb7808e80c9b886c12cb90c803300 GIT binary patch literal 417 zcmbtRyH3ME5S$IcCMJ>i0Xhn3SS3(^Xb?t7mQW%=dULUl$gzEA?#|}lDEI(A3UNuO zkSGw%&aU<`yR#pkZ|?xkF$%F4VxJHe$~H1{gs0_Dj;%DEG~A8T@mcyX z;pxqME|#&b8{Mk>DoIZM)I8q?6N?=tPJiVVdch zZFzC|!mrv?xy%d4i?%F1h+H(jkBhpg__t9<>qN4>P#ePNM?6fFk|wT%wbBv}*34W9 pwdC1iwNd5zzbga;LeGm1P@k}azV~|A-Piz;$H-UsPhb!Xz5q9ad}aUu literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorBlockEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorBlockEntity.class new file mode 100644 index 0000000000000000000000000000000000000000..f186876e1e446a9f533173884be90968ef91083e GIT binary patch literal 6401 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 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorChunks.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorChunks.class new file mode 100644 index 0000000000000000000000000000000000000000..883e0a34af2ff6eabdffd43cd369e59e60192b54 GIT binary patch literal 2596 zcmcIm&2!sS5dS@Y$x@WoO-R7d(9#yLoi>Wo5}G))!A@FC9ET*vfx?WDWyMi!%dR8` z0#^>)84gUR7cQKbfga4q00Rsh=)i>={|Ou@?2}CrX57KS!86wGzW4U)xBFJQd+&>{ z0bIf>5<-}iZ~~J-#3c-1ia#y}af#EXBuwLJ5tlK;xmf`T33GUc3s-`;%6H}kJS!k6 zAjJ@vGfcy|!r+ZW^9;UJy`(c7&lskjZPtpql~apVS{cgJHMN>oErZLQMW3@}*bKu9 zs-vb&yP<1N-AZjW%?ho`Y17oLR8_TYoy2@btJf5}a(U*a@_OB>mh_V0D8*)_LPRa8 z4M(>Wqt>V@+*+z`?&uaR*@bu^ezCANRhT;0#Z7`iFxs9OUW;T*-BD^3yJo4Ij$-Q; zSy6U6CX{S4ms88BdaY4!nx#ZK9X*@^gJc#RM=e(k+hK_Hq@AI&6eioIf103eTOcsp zAmR)YJ(<~yno6bB8VsUcZ(5q3*Dc~5)hg?b%MY$Qs#aN68*Y)P{sI;STw}N%>AwW= z1n&~h8yI<`mw$&X~#xNdW@MrWLy(;56o|BQr^9;d7(=i-F zw`D9LL;1>BMpnRzj8&}3SVxZG{9$@Sz>6~S*pTrOUZ!5oQF!}KZeWce_kZ*=Lx^Xp zR8_OAtQ5EDMlocM))T|vKW-93q!(y-A2THTj)gj2-cs!)eRpLux7(nqk47^4Nv}JW zVU`o==naMe>gm7xo?Lf1cIXQ%kjZu?SG$<&aUgWAw9hu)r0{8S(!E~l8<>nkIpa z0wK{|OSnAk3$uRjbYLV9_O}rH0B6Jgk-!~@oU|Z)gMpJ{pFwV6aO3R&`|!_SN$=PJ z8^^eh?lz9!*T(qA6rk5lY8r!-)R!0#zrwKiEl!EwAtruLUpGHsmFR}}BQ)_YOz|hY zCH{=}h~5%^aY1+$B4W6JM{x>%qA|ksF-m_J@8As1!UuD2_vYR%LDPYabLZ$B$NDxN zCtZ)rJwcooPZA%7?;b7)hzN+X-x2)-Vb1-AXb9wHyp1_#h;mh4FxI_bqwNEGp8Ysa pv2nEtQuI*GA0~Q+Vh+)lTo@9?OTSQ%`eP0Y0scuhhZp9vgAtV zK;DCYcnD^IfwTiNJOB^HuqT_QDJdo6@Q3fbtG(~r-P>L1k3WC?9l#QHbfht-V;ply zysIM*Gew$t4TU5YbSz>?M*{Du<^3c+P@3fwR`8*+Ehe$5;iiT)4YwG^rR|6fSK9KR z;&r>+Z86N%Tp`V_?F!51UrI9&{=V?d{X(;_*u1x3ZvFjaQydf-605dr%Qc2*CcDcJ zt9UKJaG^$4^?r9x_zk}2kY=LhS=`y>zOCe;GA6&W1BR(}E_u}rdcu;PKlG&RcvgqO zsJgE3D-I6=L8hPAEU#+@o#mBB=GUI@v_#96=3c+kp^dkAPm-^8x96A&v*NkrJE?-^ z(EaAZ%nQjV8qFSf!SF@qC3&cq8x7tjXM0}XZ56B4?CB0r#;k6SA%EIqsle;|me>_O z1FJHmB=_4whVs~se2mfC|GNe@kOozK|b9?V0wFg7}Z21_*jx_{Bd1QhD zLuphHhI8DqL=emrmgcGMN}1YGE_S4EyY1r3I_|kqHTUlYa=f9buc)a8L=4wYWdDal z43|zaq~1x0M}6+l06S(dxYJ_x0kH)~Y&T8-IU#z2-5fQ|Gd0oX)+hG~)*-oVu%(zl2s zM!Ln^&xrqq#QoU`?GVYwNF74|4$~w~oI8Z^6UJt*Oh3W-&y?l@X=Z<*W6_Xql0cx} z#ASUASM^)S>LnEPN=Tg>zz?a3h{Ag-bY~IQ@V0W4bTjlXig!XpR!DaKy9?Q|w2xf7G_G{!xn!Zq8r}SJW8R;aYIFC|7eZ1sR HFHQXg+ti1` literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntity.class new file mode 100644 index 0000000000000000000000000000000000000000..2d3049e280dbf89a9e61dbf2e5e40ee1cb2ac887 GIT binary patch literal 2676 zcmcIm-)|IE6#nk)kC~kgQWjcSq;`>CT?&jX6`@5aEuc%ctvy+wHWwGt11h zq){J8eDcW`AHXN&p-)D{q@oYL84{u<8clprqlx<9zd+D)ceb_&N@_9LoqO-O_k8Ev zbG~zCZr=XnQvh9Xbu{5g4F_}_M7M?>IUdsRlpGIhIHIE$M>X_m=ucn+j%hgFfD?FH z?mv@27AJKKASaiDI)*T;;#n2XsW`>JIK!5l>y=Di<<_Jy%WkP;J0&@GO_@1b39pAC ze#mz0;4nj^Ei=jx?RSfUVQtQK#L!G-TzGjtUM5L0=UTix$~{}I>%wR-Y5NT8kMV$K z9lt89!1azhfgQ{-7+J>=UVoYUzMw;+Im@k>{`7%^=gkYQS1yX89hl=Y)6+EYBCiI* zGwn*XY)Z6#*O?U_iTpxGp<`d+RA-@c+da(C4OBa{%y6zP=ZL_pknfhqCj!$K9-)}C zbqI5)FQ4b7ez#I}XPjbBHk(xkED5~T}bfU~l6!$X}J!d=! zc!};?v(w42ccpe1MJ!@fstgI=o$)L&Dm((u(mLQ?Nd&d^-wcs!YeoWYO%L*FEki2u zDoztC7_>uHxt?i#q=tCHmU(UYr)ck$cQlZ~Ch~-CLs$kzF-9JQ8Ky`YcpfiMQ0$_C zGkB4q>95##bFboh1wY_Uk$f<47B4aAN2Qc}bc#fqrNe%eUvLVdM2HV#Bg3B4j-**S zaMPaf-SVtRhep#Au9waRqC#{d6ialcUwKW%%LWQKXMkf|g=IisLIr_M!Zt94X%%Gy z6*vs}|AU1LjZ2Ie9-pE*U>JI^mMFJ(@SkD#O2~ePiy>(l8i+`X)xgl#b~mqATp-3I z_Xot>@I-#DO7v>J2WB=yHIg9Hi*D?=$Dz#KzEHCg=Vy4CN~3AHMi}rOiQ0OfhDT+3 zfqO)Qoy!60HN4E?A|!RhgumqIeYEO0vX2g|I{7(K;?`UkMSb}qetamO%~RP8uD+u# z;Zg_dU9Hd5i>;sx8*i6s36e>5+LUSWL zfJd=~Rt%3}D?Le>y^kmoB)ig{R2C5Fj;5l?XrsP>*d@Fv=TaDJPsSIZcE^)iiYAFm zXx_X|iM$Ifsm~*p)VkGqY)m%PHZLRAel-;fHPn=P15MXpB-f2uJw|7nPs!hVl#EQhvo{xLLm_{hq+QT&qen$Y?bmr!MQ60(7Bm{0*Y>ho(Agi9_Lz!&bb>K@ zkd{Vzi Dmnhh; literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntityPassengers.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntityPassengers.class new file mode 100644 index 0000000000000000000000000000000000000000..6a52eb5533d95e85c0d5207b36e393641dd07767 GIT binary patch literal 2312 zcmcImOLG%P5dKE5^{y9iOl)kx#4!XU8@$LSfD!m58`xMD538Jl17@@u#M;uXvO6|$ z&iNC$=8{vY0tY9RLoT`H2c#+~a>&ofA%UKiz@*BRh{!qYbkA%*zV7Mn-JkyY{s#aT zP&Ckui~$pwE{qx&!&$YQGcXQI$9ZHGH(_8B7ZmrQhKm|5X}HXgy6SqaoMwopGph`V zyk8LvhYGGIiktPa2ui$Mqm$l(@9^3x4_vix9VX;sH)I%E;F8;3*bt8NgGEoea{D$9 zL*Z3LK<`c4^F)xZsUzAxEI5AM3O6oKePTWFgIYyYTxpdzH#Ugy3U5deSZ=*hvy|Pu z?`?^Ij>5IJHiO}nrR3F`8%l=JwyYFLmf*&ndV^uSEtS_u8T8QK3>>j4 z0^%hPszOHmffdP}jb+}5u1Uic4dmoTy7RnebE-&UpPpw}*bi%zw3R4^>#i!YsF3!$ z@bPuN#Z4T3!=)M?IwQX z%}r{tSh7p^7?wNlhF!bVtlgB1-4tfiZ$Fi0JB^xd#A(i6hOhTwcDxZ^TUYri{QokN zOZ5Gc%?`JIE;Rx3`a0Pt5W`vc5~{{}p}ubByS}VT$OC{(A&w zn%)oK3E|aYHx}fu6&ABo~X`4igv0`^1}w{fPk$BkT{HrZ^7b zR4bqGy6G2ns7W#_#&Z@%xn`QGfe{jYlfR#8kMhWP|6TuLH~ z%QkX0t}s{~@iJtXcwBwPce&H$e%skr((~IJ4Dnl@@2T4i`TWuCV@@p839uZr1jAU> z^Tp<%*A%kGn_Y^Wtp+ad*17bwe;BmXjz{$4_qgH}KkN%v1+t<*EMISItu$70 zM@V#wfvXvGdBdHI9?T8k`lYG?|%IQ&?uH;XZ6ADR`&h8jwkBwNa@ooa_LDN!k#z-&BgXsrv|sVezCmi7*&QSJZ`MU=@ah;<7DNm1UD@NbBIh$5xJM;Pl?#@btpnQQTMJRN(B$&8hbudLg}j6E~^1?KBGd-wBu@jd06 zgbTv8$h?Rda}GIL3uZQ|VU=2%A>8wnp<62bsiuSrn2f3^A%m%?ni8hTGU)^;&)CPP ejakNiP}sml3L2QhSVU(KVV2s~Kg2AqTFGBm=2znY literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorItemList.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorItemList.class new file mode 100644 index 0000000000000000000000000000000000000000..82f355d13303cfe5d3decab0d6607ba190c2a1af GIT binary patch literal 1326 zcmcIk!EVz)5PfSqapI;ar34yip_Bk=64h-f6|@K;0!WcUC1?~OaR?h{Nlg+v*qb13 z9QX|`T)2V+0&(aE@FV;Jr^2jTkWj;+0xsT}x3llf?9BSh?&loSi%VYd!oF~%A5^61RozfBq$-{#f^wIK zp`fq_RmbnyVdu)#r}i^H=(a@5m3DK`>CnPkye~yyyS;wbR(xgO8;XFSu(8}&zSOwC z(pbrj6jG)7j#5!+j<^VuhtZudq}{zN%iF@~h!(@6eAN@u?oqi;z#mIH6amTF!+lMA z^JcBa+hxDk_Xl2Uqf%Ko+yMqgX{EiUl)O##M>GtJhh<5I{vdEfT?E8fVMt0Iw1tfP z@h!=n&RyP*+G4_Fu(qP`JFe>8?4Ry)QC(IF30zDe4%0+Fg#{EC>i?%x47GntOs#3F zHctIE7(da>h`Cooe&cVGU>M_$Bf>DZe0gb!;r1b?=-`mjT-7m0?>k2CoyJ(TgDed% zs5?nQEb{J=uhTkKD1HPhls-Uv7X^*cH?6kx1Y&v;mTn-UeJ02Z($L&B(xFh;`|lW_~< z5!}Wd852lINJ^NLFvSphpqsk;kinlw<`@ELt0)-yRoxVuwMs$QSza(`WI(kvZsfSF zd$>Iqa1V5cVem0`dB$|ALUS!!6?I{38@wTGhG@n#g`GCI;|QAhLe;E_;*^(`kCa!I zZ4^aOca=h|TqeVdyy^;D(JNI$@hH=lSr;}9Ir&sRHJ{&^%g>FU6>Eh-(pwrBUM5si zxJrdqq1k-jRUBaxl~Ql>D4T29EH9<4O4X{F#g$AZ*_i|7ORH2FW;%6?I9AQpM9xbN z%P>S-ZkL4H#J#&N*UB5b+Dxy6yA00~-DfPd;_a;O^(@2V^I&6;cbkiNs(Y0&a@JPO z9P&DkLPigjS*su<%tWDJRzfO@c`Qh{7sY)nGVJ}g!eEGbLKK6WC1tB{NJYx9dA{Ko zdjF|QhPAE(q!^|}c>@aL}Uunm@)Z44wYG&x+nkF1)JheDWt?>RFI_reO&dz~THYStI;U=Bg zVbGyKN4Ot8uXPAT2`OY5+2G_i_&(Ez554pbd4rKR=%epwYXbT)K#1WYF45a_K0*)y zvV&6t{+Rp~fsg3>f*_&ck?#mieWHKv z_z=!iM`=fAd;p)xae8hxG$1H4!GG@EbIv{AAAA1z>(}1_Ea58|!$`}BAsxnoj72O( z2=iVT?~D6`Fz(1$#)^cD3>jH*d?=2)0(~!nReU74)+FR4tV`Hn7}rhLaQBObscYPJ zi&m}N=Fd#sW|%FQx~sMX#pd6*s-xR`x~=Y|tLeq+!v(d=BPg5teuiPhHJbW{C+&!o zP}VRF_b!7!k=$ko5$ zr>$$QW%q47w30hFU?hTB@^qXZfl6%(9zxy>7T_t+TsJ7q9cSOO6<= zc2gCSbCyYt5z49de5)=@pP`Z*mJH7#hOZN6gsQYwsqjY5YPGG7SM zFoLU8&y`c^S;45F`HZ@Rf`TGS45|O#Cc=a*1)t(G1rJeHP{HRCwiSGV9R-i^CDqdZ zUAYX=e$KaQPpGFDN*Ak@YUo)19MkF58N=GZI@1iRg9>4|#5GNKoayw^Jk{lD;$%yl z)vbStCaJ@C?;Nj_!>yVjwy zkwo&OuVjzYx99dLYEJTqrrsPh5z_^|!L|L$ew#X3J_;yng{|CXb)!_tS9TbRgHMjW zbTP*@Z~imvR7U@D}~_V_1yj>a8P;{@diVswwC zUci@%`ClUN3xcUwsQV%PNF*O7=)6pfkfR95!x)ldxJEd|W5spcAc&FLn?1455kQb| z*_l}Q0FjkI>SqLhgS-NQ9LRFm!;+KjF&E^~slrJ|c8HK$w~5#P9Fw zo-gdC?WX96qoWY>-*PglAUjZcHyBPog literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorMobSpawnerMobs.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorMobSpawnerMobs.class new file mode 100644 index 0000000000000000000000000000000000000000..12cb89367d2099c61fd6bf145bf3fbee68227555 GIT binary patch literal 2702 zcmcImTUS#@6#j->PI5RXO+iZ)tCV6$kV6ne2vtfzO$otDN~^WTNpc7Wax>?ErO*8Z zee<<1zP4R0y4tn+1NtNSKiai=`6h{Cl`1Uk%F4{1J$v@-{q4({U;p~)7XV{e)6s=- z9o-lY;DU|`Tnv&ksbMOBxQ=POufvZ^YPcN0jN*KthFKj6%&B2Mh%2}nz%_L`8Ni1c z7Br+ZEDChFcFCHrxVF2!Sj{chSm=7 zPbLQsc7Q-ta;__jbg7{tCNO+Z6=GdLBn9-Qs*>%v0+D@bNl}&_d-CO)K+vgf*7Mei zN`jy(>qX0L&>hRJ%x^5pS|ey0mNZ-!xEelu9Aa^mGHqXs2+X|>ZNy-?;lmYXwm|QH zCBX2y+>!=*@HVR;vqu$Z_{hKwEE_nEw+QC`D}wIW1q~SkA7e#b@ri*?ag%{=6xj8u zYq8>F$uV#XpBcD~&xxpkJIETi3#lPzpa5F$Z2`}#HX+-KD9D;7^MkH47T{M@bJ zG+!j$U`Fr{)h;=D(59LzIVZT9=1T1yi9AAEB;QO$i&LK@YqsNfd#~OxTqj9q|zaQ`MMP_mwz*(9+gfM@D@G8?= zZYe542?dNqlyU@t)DS5T&XMkb=TDd#hQ;sb*E>N(M_M>ca#rF#A}V%)^eb%yQh|7^ vDe&|*A7U7796Qh5Hoh)TbMB)}U3?k7!yuSkqcgyh6G;2jyKw^fnVx?D^{eoS literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayer.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayer.class new file mode 100644 index 0000000000000000000000000000000000000000..59c73f6e5030f264187dcf8787079aaa309d6e51 GIT binary patch literal 1996 zcmcIlTTc@~6#k|y-R@GM7QqV_6%h(WmV$~1B686*Ry5F%=nD?pp)9n!b$5#PZ}{dv z@KJqG%bYnUbG~z#@63Gq{ox~k%a}9JjEe@MxEMjd zfdM2U7>r=ZKoY|`E@4C&%?L&{q%@3a7-tAi+m0<~7=nqxRff>Kn-dJJ8QT#{<>I>V zvV6TjmUzascwv=$w$gWvA-QS$3~dWs^0ecZge6_?L4j9<#}G|Bj_~FS-1h|?TFqE) z(e$^kO+GQ7x?UkCa<(+r%iG%|c#fB(@Jzc{Dwqmw-gS0_M<#zQwU!!RTOL~*>pLXO z6oY2hA~QTrWE>&QBIRy*d_$VP@Ce1+*@ZBd=CWCypLdHTx9sGm(&@qa9H>iHvBWS^ zubb|>WzQ0;sxK_fpiA!Mg{IMYhdQklKZtw_&y@@mM4hr{&@CcPb-+`lU- z_cyYY5|OPVaR~0%Xem4Amm;W<#-Y8fU5*&Y%-rl)tid(=Lb} z+J_M6Z>MBis0p>KCrPSPs$_O}$sM%=e}gpPJbJ5c7sxSyKD3kUCGckYfKR}{S<(@U RP=^O_IjsKX0o<59{Rf)7EGqy2 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayerVehicle.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayerVehicle.class new file mode 100644 index 0000000000000000000000000000000000000000..29b4007aac95041bbef75846a41f79b7e9c04b39 GIT binary patch literal 1965 zcmcIlTTc^F5dKbEy6n0L7OjHd1*^6cSc_Mv7h*-zSc`$Ci5i2a+e2B~?$+G}?Td*< zAAI#m|AqRX#s`0ZKgu{~X%rKDXo_jNXJ+=y%r`UN+4JM)x9=*`m17tO&QnD-E*5 z3XaJeW$s#1?-(Qgy5%v9-rzpZ+g?kUzT@6)@V0QvV%;*Oqn@{I;pQ6L^91dESTLQY z;ngqAJu#j-ZlfxymTy!x>UCOpmA8E18dkH_Fl5l2V{ZzVOx|i{HFI`#d3JR+@$YO| z2F2RK!SE_u-R-esGhUonxZUR29_t?=Wb2-fj+R}bF+Sjw}PfCm}R(??7fSbtekh~ z8FApoZbW0yR)QjKT5{~;{~F)SW4_6C=onzwv+OujWWW>!XLaK5c^wyUk$Aai`PYxZ>k%v)2UqN z-fhudS}V0%G_82D@Tc$<-?i*oHlMmr6CxJoI`k%_J8bLv(A@61+=8fav%Q5}+pa_x zi=}+&9>bm98T}_NeN`5E#Y~;#rYSrxk-2z=j@;W_IKkTxcK6lUVb=Ln8OP}6&_GD( zA_*fTk0@z-Ni%3=wDwJYLFgk1Aq>(pDvj!M43VsFZNNV4Cyn6%;`Efx@6bm-U^*QO z4{4tfd5;q$en#JXWF!)cc5H*6ph$IW{44s?AIKpbB#BFB^#%5*FEOmX!cp}#((0Qa z={b5gj6*m`|Al*zv$^f*eCQL0EtZLZZ?o8>3zxAss{g)X^zqqVoQo!ra2hFI})9X8-^I literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorStructure.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorStructure.class new file mode 100644 index 0000000000000000000000000000000000000000..44e0f969162127888eaf96d2519833fd340e9f97 GIT binary patch literal 2405 zcmcIm-BTM?6#w0PZFX6NMxjNERzwX@vV_*skVu)as1r_~7{Li~o)fRy~_wXdRph6MWcv&$)ZP&-vZmU;q5+X8`B1 zuHXqI6bv8{g{B~i8GlJCn8i7NIWOUrC@#pD!$k!t%tw*-nM)F0m9QY;GDGB&X_?*v zLohzE!4S&YWx+6@o0iBo>m}h7c&SDwG2J$JZG$_e&+i|Gyj!NrFucS)p0nJBFg)8? z_nfBTH62n?bCxBXY>m6FAi0~mVb?XcdNK8m_O9*J%A#y~TB%vB(#FfY;R#1G>y4V` z8_e3)ws7dkEhdY}bH(ek#o6)0J*62Wv+bYZ?YM3UPpeY~hQl{K%@qzA(zf@lX!%T` zz$;n1-msfiIi1T*98G~iu}YrDD>c*g7$&>Y)=8GaWLxy)sK9LtRF75=NrpsMW;#(* z!;E@^L3Zt?V~7pm5bbfNBD@yezwU9Py2=}^R!O)*vmhbEa4p_@7m{gzRs!$MFf1L1 zHLB=(D~)B-pS98dYJXyjZ*vtV5Mzi6%QHPwxGJ((QgIc_l%Y7wML=T6AFnfp{>RY6 z5bvfy{@^lXdX9xgT)oBJ6|u9nS=eb%n}_52LDF<c)D_Ku+gyA<Xf*Rm_cb`f!gzJ&uI9MPvS zh=6}b5cec;8tshs@Z=8&d`mGCBF+7cDXeDL#KEjab?Cw-7 zI4JKS^bwYPQrSazJ`}tV9tw|y_7J&;>5TG+X`uw)KFb3$`*^paMYt7=7|57?ST{O#T!J`7_MRpJSPLUH%d` z}UlgqPSKn3nMJ?+8D{$;Wu=<_S!+ zdqF=i^vxkXzme?lMh>?HIw6EHiK&*_SyBvOno{x|hiF<-I7!LIiN|1+<|c*3i2rw# Ig1$KNH+eRPy8r+H literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorTagged.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorTagged.class new file mode 100644 index 0000000000000000000000000000000000000000..180915ed2fbbfaa2dd3c45aa8e19003619894f5d GIT binary patch literal 1491 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 QI+3G$mhn9C7*tr}KQFQ@P5=M^ literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$WrappedDataFixer.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$WrappedDataFixer.class new file mode 100644 index 0000000000000000000000000000000000000000..b58369ad6f5926d234d16655dbe8c029d327ff57 GIT binary patch literal 4486 zcmcIo>2nih82`N?$>!LWv(;D&f)&$J2`z}w)D|hAm9z+{;MuxOw(Zhf>~4U1izlEU zDkylM$mj=0N2VfFXB>C5a|{8hLA;xd`ipg)=Wdbj|06@TY&|8Os!DR)2<-|)XrQ^H#;(#W$DC7 zmMwnWOdira#RA=+D|lX@qGzO_@6rc!Q_rO+?{LXtSMgRdQ8x`YKAT}ia$43%#XCFe z=fDt{m&z6dRwr`09m~>mDN`G;W0r2xtFis#E{%0>?&;A6JM!5=zL-l>fy%UQ8K$1z zO~)JgoPg-03v6m4Fe}q5* zJuQj7+I}sTk%_vaf3Kdh<83!89!gTo859%3DydRx3w&LE4%bbwh2go#v^l{M0Sq1tnKf$hZ^8E&}b19Nt$kk4kvr_aFZ6gy) z7?v&1U2%BcKjXahMyoG_{C{FHsdQVM%~8P%v^7gWGBu=UHCCPItkuqPP^?%9l_Cm* zhDkcrWSb#-MC~*$PHAPUWjYFMlKr!smZ;)()Ty`wFRECM6)IlBAr&v<6$P)Vcnz-$ zY%iC`lpIs>1`Z1}UQgmEIHKYx-c+#_+h~$mMut+oR`C{&Nqvs1SdAtXZ{q~Jf>XTQ z@Kf;)-c|7)PSRT{PRW<|rCi-*t2)hJDn7tzDfSr^A4)lH41G7^RD6VwRXhxi89U1s zedaj8w4GV=*$rp0{=~qh;1hv6XF;0TXE_5+I;NAen&woec~Lnxg|t*kw>bH&;q13C zT0f;kuu(Bt0=9}nt$&OrGh8oLPx!=1y9w`7EoDfvy7hzf zgg56bm9(?W8@Dr(7OmGCox@%;hQGPYI|F^vJ!_?Xl<|Hf@YHqk{SSjcWYz@X$I?=M zrU|YdeqpgB0}B?&BF%3(FMoGnB~S00=>LNT1moTrP@glqz2=XAxXQgv| z2tn5KO1y%4!m4@3D`>!7T;)!(@Q@^{C07y_A@~sBS?^`|R*k_gFb2hgpAl&B)h_h4 zpTmZT?-#6X{2sxd5o+;Qc?rFY@Oq^o;*0oetCUMn30B&EM8%_*Q5o@H!u+m=@8Dh4 zSX<>C!vY_^B?qq~=L(108(56PRQ(8HN72kW-i~9~jN{mW6OQb=h!>@V%~%URpSAqB zy&H;@)YYdK>v0dYk+2Qe=xE!E7UD@$^&-xlmz=hv6>ZeBolw=q-$eZT2nj&^i5&{L zcks=FE&Q?hlngJwHKRe{>`SX>pT@_r6AqBM>n;z8G!|NK_saLXhIQu+mPNyOpc zkdqu7S`LS$lB&a@rX>&wl{XoKPs|bnVIjr#qWys*(O%eY4L!guIHCz+^;J@(h@16hv literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2.class new file mode 100644 index 0000000000000000000000000000000000000000..0e5ec4fbb80ebd8c56acd1d4f3921cada978d299 GIT binary patch literal 26822 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 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class index 68556cab91070ba9b83d00f939940eaabed68d22..eeeb7f729d2ae96010126434e0ff4209e6d51d04 100644 GIT binary patch delta 13 UcmdnbzMp+V4l|?NrAOHXW delta 13 UcmdnbzMp+V4l|>~9*8JKupDARFe;*0 z5Dhk@SpgMLL_`5a0a0uSh=7#e>;)pf_s876EweM9`ONIz&EJXVccTB3tDCk0KohI0 zjS+ZF1c41cLYs&<2$RTC6kt;zDbwvy6yzb>G`(g}+Z0S8ib6f)Qxq0N;S^y8Bh6rx zP0?nsmQ67fYebw)wW*E`Qz+iF5^O&uQj!hvl&mPlJX3AyNi&1#M#zE;%CsqqvK8f+ zXRZ--ji_fteJ|xv1DhIBBOB7Fv7#n6)TO32HKXQ=TG)_hyh@^$M&v6hu&EWbHlk4G z_^FLeZK+)lw5Il6DxwZHb);frNr_FJsI#Ijwv2T(W2L6m&FHzsEb6YPhYdy4)AZcx z!GVf;*-%2gWl!qk!NDFJVutz}TlyK%KL}IkHXBCJfFK%3gM!FEkOrIP5F>^fG0ccE zFAb*=UK&Z|UK&NCjTob7tQQ8-I7Q>VFqkITG?6Bmp2>=)D4MEhn%Qo;q6$SbY$&Ih z;Q(}}O?S~8FN`O@qPYgCd5Z3~VIs}9$={6bQMACUyVr>O6fLxA5iPc1IxR8cew&sG zATqYh{OuV;572{NSWV@|&4J?pn&5nl7q8hO%lMkE{Jtu?+q@1+;0T+up3FDiP;3lGuDMm%rRE41DQhh9~* z!AyEB9Edi0=?!|*rnl&A(|SkICL10zbKVUHrj0gKnm=0Rk7f4gDpdp4}4 zRD=2ZiaxO6CHgRkKBA8m?XYR5q1;YGxt&5eSWmlb`h-4J^qCDCX}6+1HoPeu6EyZ3 z@wp9+=?g{s6n$yKyR_ei&GeO`1B$-3VH+K^VLN@J=vzgHY(IQJhi&+fjwt$0(f2m& zprbbIq#qRhXvlQThEJ)tqT`BA*szCwvSBZsRP?i=Uu@V%r)>C=el=0}P0{Z`^auUv zq0H$#<)XtPSM|r&fD-k{bR#Xx}fNy^3x?7j?uq19H+~Qt|+?dg%FYj zKU1n=P>eSGCJ|z?A&A+eduP+KgaRC3M4-)zJ>oP6DVEBxnY}iJvo^keCBAa7@%kHa zl0$3`WuGlR9}yop%w~T$OTE}ZKZu(gX>$}ui-TOtxO!4t;~3-Qud<`-1jm}aFsiTisJmL^e~641&Rxt%@M!Y3l+DL$|dEj>ea~R7%(1TUY3K6Gn`){Bb}$B zBC1+M4V?c=@kgp1bJxg%B31JFjH|i&9`uOgmh<~N_J+}NsI2G zxhMXl`Bv_wF$)FE-U!W{viKzD^Exs0nriODeKq&v{^E@0+jxNHfjmg_U>>4)sODi@ zrg=CQA>=q=D#01z(TN&!c!cJWT&{T(_f)3$cyHJ-8Pk&e;|n z*GfXAc^2Pp#B9xX@c$%UM)94R@8UU%n`!p*T*dP=-_1qF%=wD%(Y!#go0pJPYck)f z`95A~#3GH0afz9;*x8;?-@AnG*Z4dBAp{Z#)13H3HF&A!W&D7~7T8krgZz-@huP7* zoFCD=0-Gv+RP$r}xaKE}SZTzQMyxVoH9syC()<)xDsHX$X?{j=OU=*n8qLq~T4!Ej zOyKjp*5J_7mm6gOm(b@MlU~rg&WuDlNxn$uY~nz^7w;2XIy8HcUqbM;pFFu@dd0M| zDc#B|#!MbLJv5MC_VHSIyyD~a;xNCec!TEG_;uq#l`tpS+1||d82C3Lv~+2ZkX+mI zhCqTx`Aw%?a&u2xY^Sjo_IBnb=lI_;YTh=Hc}Mdmepm5kja{)+@fOWn@khA-QNu%?6IoTD^e^&g9=2QHu;@>p?&VOkBlTSMnQj4v>5b|6W zZmnxO-=!|`oH4vP%jcY_Y0X0h^52TjYyO8X7|cu(B&7!@^d38*yyK*bu@$pTfl++X z?0-q|znU-e73W%7AzpO~)1!m0aixH0fs9)yF(~$s#paLYyqey_8(;;RKguMSp1kd!_fA!@|riFwnXhb+aZZ zHqiM!Bhz!l@|qP|w#jsgGP84!SSH7;5RFIhJA{b;fbKnJ+T>Yf!zYw0D^y!PE6jN` zGdVEaia>~V+QmgX`!nM((v%)2IxEq8#ELSCqHowYGAr3T%Bp4hVs7}cF)KAN*3^ya zOv3EK#3ND(tT7Fe~lRmX}~R)V$?tt7+rh0c)dTK;ubvbItLAYLcHh)7jdnzqsn zqt;m&%F5JMmLb(TD_dDP+R8Qh)`_bkf{mzaG}kk&`pU}FRs%6s{xnopBW*PnD`hV+ z%lDu6-G`4WA5o#LCRWn`Z8fu+I~TKudRhnxq^o7su$+HFJ^5CFoZ?ois-gKWvenw~ zY)D}O9>RcL&i+A6}C+u2*yr%e=Lo2v2cLJ-?l-O;`%Fr=Nf+FKnp{)?9lI713^ z1mj|>MB^pApz$B6OIGKm*xAYNeAVjWR`1TWoS~gVoU$&(80);yWorB!uwVv+!(6Bh z^C1K7f%DIiP#LAi>xc{x-w$M2sgO0p2$GA z=i!@H()E?LDR<6_uIZUiLIA9CXG8;;HJFbD@-(eh*jhB$C^g#ov1>-=TG9CYO>>ny z!^~CgDl=Egi<4KH-|;mFfvTJ4*2eZ&Br`)G7&~A`vAS6PX`ssxt+1p>VJGY?Jz_I< zk*96Skh8wDZr-+=v;<=}yhTPqv~1U)4H3zGIkhCO%3eR zEhFnF*bJcZA|MLp55B7DQ>9)*&Q1pHa!Ei`obr@pc2qeJwkOoJg0UU#la2&e8 z3Frks!2mc3W8svmcNEyt7wuvcB(_h!9tG3thyBHxU>J_K;Q)z1I1I*tI0#s@_rt-` zvSg2*I7C_jon))7I24D8$qk?lmf>(vvTY8IkWhJCND~0B$<9FvM=C5=I0_LJj#fBE z;aJ%maU71X`sbFx=>Jo^IW4xGfe1JYv2YF&;crNX3(y=cLNQzttN(>@a2ck;6_^cI zg^$-@xzMZ<8D2(9A{+plF%aIvAlNN;)qUuNBdFnb42CNhg25Pykr;*X7%kV6T3CQ_ zE+X4y$0L4d?m`j{yP?FTQW$K8{x|_Af=>)ByaAK6s$nvHWjM(YRa%pAiog_sxh`}T z#A3P&T>vCvq6=Lhq+_fLoszv2PQ_{95yvjzbgTe>kofm2&cK<1!8qZ-EW91O;_Ggl zEqz)%{s`~D|4DR~!;5&Q^o2krtj4=!<4~Lt=s0q)K6Ef%Rlv9+XPK=!Feo05*bhYzz~y z2`t8z@EGR9N(qb6I|vLQ3hx)a9+&_LxKxtOBQ6cYW%z(_t^@SO2k{}{Tq?|vNH{_u zkn&Moj!bJgJ|d7v%kN@nD#|JsLw50MA`7b3t*BA=XpOqZuB%&)k5?;^m40B?#VoJ{ zD1}d4h3*PhDtuDms=C*NC~~$6(^pr6Du6sCdlITjVfxefj8odX+}~Dmqdmk+;%8$A z!L)FRPyu-dK<=y4DIE0-y4vxX-lgeR|yKS6RxHFT|2&=|(MxobSHtg*ZDM(#r8SfNan7#i1v%drPOBIm^l*ZnC{BjyMzm*Ey6&!(Ez`5P^)UET5vMs2}&ec~WE zC+?dp0y$2uXNtD5SHS0DK#YKcEI zdX1#V&G&?a8a)Zu^^kext740dAEH+y;GcyPOE` zK^eXeWAFo*g&)Ek{75+Yu^dD@;91-$rFj>;BSvkc&D1rS3OZ@mP_QgYTTpY&na&ev}SLZwMsEdLr4#f~ED!!1g z6^Lj1gz^EBZl$8m1S?*O>wf%7;;p4z9>A{+GPv@FztTD=Yq2JP)hoZLS@|tAsxEKo z5Egh965J3T5_VsLMi;>oRsEBKcQ_#`Dl$asnq2Lj%ptSn?DpVkf$XeUbq+G{Z{hZN zDHrGDD7^^XHOZHagz{1w*XZ{m==j#rHxdI9}pfkjd`NkK4qAc}$@Rz7#I(2q0>pkNq8 zA@T(`6lRbQ?xZkSLgDZ*MaVbBNcnOY1zRXuKIqkg10>foiiO`O4$e|-B&vf!6pvw) zfYFqQ%_#}nQ!;j>6fB`s^xr~hIE>P9G-cpy%EY;pg%40RuAp3eh3evZs)rk>K@F}2 zQl|fuBhV5)l(;33#U;R)sF;|Ts3?~&g74ohUs5m1KupwNh3CmtRh}tgZi*T9dE}e;aC|sWK0Na-{q9Z6kF}5?-cE)Ln zx19-^5~+q2Nt%+WriRH>%W5e)NU4;jA(heHP_UFO08%qV}jI5 zQ)_Ay0j;R5pUUVeP3@??wWNclj#RFwla{{Dwy%rTy4rQR*-70MU9F)V^{_2HeR!>+ zUK+}&x9mxMd^pI5gKbw|YfC>Xu8F|f)L%m-4Tzv?X_L*cWJs?0Fk~$ z_OV9<-9wB0u#zgRoA=s|`)nZYx8eaSTq_>5;vpNtB@wigmRa{7js>I@npV8GctQqfvPPb+%H5BJlvRy?WcIeK1$OY0P^w}W1Y z1)`Vy6rz_ky+W^A?KMTOYglH-Y>Wk_mo%)h4{s>itYM8+-}F)NEz8y|8lIv|i}_YX zZ)9u1pmucCd5KGU#;_G{QmpDX%8(U&?1@6uNqw$TAaUn@GOVF!JqVJ96@ zbl8&VTMZvlZ$;lJ`d-7w^n-@obVSjQihk0thmLC4OUG;!epd8L1RbXnKKj*S_?x2N z75$;%YiryA`cu(gicV@cM1N~IOs5q6qk?o=!}oMX!w+;;(Z7n$`5}sA!codpbV1QY z4aX%y3>qRBZMv6Rjf4WsRydl&I9!}&rC2J%W{%JlU~PThE55Sddi}XL$wqS|M``i- zfcVJKnu7tBda;8JiJKg&IgaDSK~Au)9ue0#(K>ldcJ!R!8g}m_F`tt)*W_B(n^R&u zr)W-PsU+XiS+SkdHT)zFaE3KSYDzrUR-EPIY{fZ#Op@e*QJkxxW+mq-&i8SFj|(-X z*g16+*Hv6E6bQ>lr@rDMw`F*8XmNNxIT?~zp-sN?6p%p;q#`M9sJK{hqtFh2H%ci{ zEJdeS@=WT6;wA`T6(cGpPetLej}*4)N$ zTP{<4mEm^W-e5N7Ak=YRjLUF~QX-=|81BgBhCAUYgnYNmm*&pV;qJtg$hgkj#b7Q9 z6kQE>uP3ORCDd9vd4TYsEMb*oVgp>V_wDqTE-(~O@Jnj~y z*AL!pcoE-Yun9IbyqNDbd>`L$_yKkeKZuPLKV*0bFEzZ(iifROZp9;3JjzRjP=;6V zO2wsyALCVun;Krtj~jl1*C51=t+=70XvXyG#}{?4n4H~V;`FJr3_oeR>QqjeP~_%h zr@PUKz62W%p-D4q?Nf%=+7a>Y{iX44-HbszA8!}XGTq+-+I=M>nV;ro+)pzSGoB6b zn&@zTF2K(V4!lnBdc!a92J6&|mQcN#<@;<_$I*fM*_!GmQ@*c%|4e#U64DaX95o&m7 zjjxzEx~Px4sI74)*3Jri!CxBwO19zy{I%kP?&{hP#SOP$ePj3#AGQ{LYnh*!o#l?t zO340>zYpLkfkl$z2>+<~C&NeinBt!e|H8)&pWt8JC$l;_zabO}ZSvh3*?0SYx0L#W z|EvO~Zeq{z6|+W8wJiQi@kzsfv#_kWmw}NvsWJc9ZBHvcWB4rpi_r8^Poz64Cy;jz zA?ClxcdD2+Mxt-{Jg>B%Ua)g7UYYN2=cN0=L1}jgprj2XXd`i*SiNmKCb)GoAZ^dYX``q)nJ^crq2s=(+ zxx?(df;tBrzil@L58&6AIqOBC@0h8RW>yRzKTl{O3!m!6toT=km}(i**Y@MNj6SR zr=qXe^)(UJNK4bu!-fAu`lu(0SBf-ECitz+y=QY59-4LXa{#dS6Jvy>RO(> z2n~is$a^o}0Hz_WbyYvFehg|9OSj2m87SS1%6kk#+Y$Bzz`_?}sG#9Ma%R$cC?= z0UU%5@C|f?AkiGzqZbYqEv%Dl)fI=}bz*V@XoEv>7%17c5Gy29J`d6~z>BhTgu>wp zD;17FM1><2j#4;UHb)#IcbKs~hG6iRc=NN^b{yj11SG?+kPg2=4*UsC;Vg43`N&cK6k7FNM|cpff52rj~AA=cZ-unQg7gJEzG!{G!fIFCMzlo!@` zjK)+9$SoxXOXbP3ajWcjFbGXONMd0ZlzUW)fz2=g$Kp5$h@q`7!z5Z2Otx((j<-Y= zZ30ddnBuUG2b}}Sa=Wt7g+V%|d(eeL4kmlhDcMWmB%BOBaqKis!Ko085dVI`X*gXl z7z_Jw2HpUE@pTu@lr|$CzlS&CEQ!v8@GRaWZBgR+O1xP%j>g&Ihs~<0QMU*qEu))3 z*hN?Y(U;-BRkp1PK~Uiwg>x0&=E->~9_IqI#d9+AUl^S$l(Z-PfZn6qBtZjAh7zm^ z&9D}<#1t8p3hgn&1FtHTJK+MnLvXO0`XIak+n;TOcBiPtmcQ9B$6y7E4`d~by;oXvKK5=OnF2Z|+bM2uo zF2;L>b6GG$B5}W94Y1;JoJ4y7U4cZ}f*yvpqO9;RWDl9T0oLuZY8%R=06i@LXyNQL_^j9v4aNAJSj~_Cb-fbkc%Vc9UVt_VpI5j}3aHqy z9$#?BU$Z56t=KS7Y#1!|4S^&a3i((8^>8>e!b)Mq2xx~Rp%O>ISg8sVa12bBth)y% z2qPv6#V1!YqEZ;KL3j`$he|`wS_O?@oR_8HV)v?QyH{P#Qdkufa=a*p$HL-E;3dIA zd*13Qqc22tOjV7IZ8@k_(Ms9jF(La(NslY<32D{qq+MEv>}y}>=|S&caD({pqFgpYQU+g^ zK)oW9UxQM7T{3VZ^pgk=5TGk?GmH_WX5w3LD{c{{ZiNT&ZFmCTk<$DwY{YG_72kv1 zxE=P3sYk@f0i(tPkJ8omZT_=Q3pK_QstuXjdwtTfOr^ErW@8Y4ahn~iulrl%IF5&VH6iEaL#E?u5 zWXgXjg+YG`hk>MEF!|(jZ3N694YSD)cawn!C{jKkM#*QwXn2zX^7SqT_ERhzq&PTE z@$eTVAWm) z7u4~t01`c@<6R3-{P|a&2+v`b{MQz9YuoOCPdLul_uD2rWll%uDhcKc h>6XeuQru`J-AJ=MZ8<$ck9yh$dXY9<(l*hC{{eg0+*|+v diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class index e8e38065a243a964ddb4fd2ecca5b25841728727..49476c724bbb7a0ab50ec017f6d49e863d95d180 100644 GIT binary patch delta 13 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 delta 6317 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 DY@ypJ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2$1.class index 86e5c9d33209d9ada1177003f61c4610dc7fc2bc..f281d517b5ae09bb81af4f0e2f6ad4500f91df9c 100644 GIT binary patch delta 13 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

^SKwFf+cK8A_-o761+@NagN~Tp! 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1$1.class index 66d9acaf192621175a8b1f3e3e4e73cb8f1d4e5a..d0a7128a6bdf4c6ff340c420e522e2ffe9250d70 100644 GIT binary patch delta 13 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 DgADgI delta 6272 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 G;{FdTo7xHh diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java index 7cc6e1009..762884ab8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlatform.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.extension.platform; +import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.World; import java.util.Collections; @@ -39,4 +40,8 @@ public abstract class AbstractPlatform implements Platform { return Collections.emptyList(); } + @Override + public DataFixer getDataFixer() { + return null; + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index 1a25497f5..d9391ddc3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.extension.platform; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; import org.enginehub.piston.CommandManager; @@ -51,6 +52,13 @@ public interface Platform { */ int getDataVersion(); + /** + * Get a DataFixer capable of upgrading old data. + * + * @return a data fixer, or null if not supported by this platform + */ + DataFixer getDataFixer(); + /** * Checks if a mob type is valid. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java new file mode 100644 index 000000000..1318cf9c5 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java @@ -0,0 +1,34 @@ +/* + * 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.world; + +import com.google.common.annotations.Beta; +import com.sk89q.jnbt.CompoundTag; + +@Beta +public interface DataFixer { + + /** + * API SUBJECT TO CHANGE. DON'T USE THIS. + */ + @Beta + CompoundTag fixChunk(CompoundTag originalChunk); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java index 2c9cd41b6..b9434ff0d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -35,12 +35,11 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.storage.InvalidFormatException; +import javax.annotation.Nullable; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.annotation.Nullable; - /** * The chunk format for Minecraft 1.13 and newer */ @@ -160,11 +159,13 @@ public class AnvilChunk13 implements Chunk { * @throws DataException */ private void populateTileEntities() throws DataException { + tileEntities = new HashMap<>(); + if (!rootTag.getValue().containsKey("TileEntities")) { + return; + } List tags = NBTUtils.getChildTag(rootTag.getValue(), "TileEntities", ListTag.class).getValue(); - tileEntities = new HashMap<>(); - for (Tag tag : tags) { if (!(tag instanceof CompoundTag)) { throw new InvalidFormatException("CompoundTag expected in TileEntities"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java index 319503740..1243a25fb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java @@ -21,9 +21,13 @@ package com.sk89q.worldedit.world.storage; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.chunk.AnvilChunk; import com.sk89q.worldedit.world.chunk.AnvilChunk13; @@ -42,7 +46,7 @@ public abstract class ChunkStore implements Closeable { /** * The DataVersion for Minecraft 1.13 */ - public static final int DATA_VERSION_MC_1_13 = 1519; + private static final int DATA_VERSION_MC_1_13 = 1519; /** * {@code >>} - to chunk @@ -102,6 +106,14 @@ public abstract class ChunkStore implements Closeable { } int dataVersion = rootTag.getInt("DataVersion"); + final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); + final int currentDataVersion = platform.getDataVersion(); + if (dataVersion < currentDataVersion) { + final DataFixer dataFixer = platform.getDataFixer(); + if (dataFixer != null) { + return new AnvilChunk13((CompoundTag) dataFixer.fixChunk(rootTag).getValue().get("Level")); + } + } if (dataVersion >= DATA_VERSION_MC_1_13) { return new AnvilChunk13(tag); } @@ -114,6 +126,7 @@ public abstract class ChunkStore implements Closeable { return new OldChunk(world, tag); } + @Override public void close() throws IOException { } From 931b7ee694a003cb37ea6fa45c10f08a64ffc239 Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 14 May 2019 00:09:21 -0400 Subject: [PATCH 134/366] Update for 1.14.1 --- .../impl/DataConverters_1_14_R2$1.class | Bin 0 -> 294 bytes ...DataConverters_1_14_R2$DataConverter.class | Bin 0 -> 440 bytes ...ters_1_14_R2$DataConverterArmorStand.class | Bin 0 -> 1352 bytes ...nverters_1_14_R2$DataConverterBanner.class | Bin 0 -> 2169 bytes ...erters_1_14_R2$DataConverterBedBlock.class | Bin 0 -> 2992 bytes ...verters_1_14_R2$DataConverterBedItem.class | Bin 0 -> 1464 bytes ...Converters_1_14_R2$DataConverterBook.class | Bin 0 -> 3369 bytes ...ters_1_14_R2$DataConverterCookedFish.class | Bin 0 -> 1576 bytes ...ers_1_14_R2$DataConverterDropChances.class | Bin 0 -> 1587 bytes ...nverters_1_14_R2$DataConverterEntity.class | Bin 0 -> 5985 bytes ...rters_1_14_R2$DataConverterEquipment.class | Bin 0 -> 2356 bytes ...erters_1_14_R2$DataConverterGuardian.class | Bin 0 -> 1422 bytes ...verters_1_14_R2$DataConverterHanging.class | Bin 0 -> 2209 bytes ...nverters_1_14_R2$DataConverterHealth.class | Bin 0 -> 2438 bytes ...onverters_1_14_R2$DataConverterHorse.class | Bin 0 -> 1602 bytes ...Converters_1_14_R2$DataConverterLang.class | Bin 0 -> 1393 bytes ...ters_1_14_R2$DataConverterMaterialId.class | Bin 0 -> 13785 bytes ...erters_1_14_R2$DataConverterMinecart.class | Bin 0 -> 2029 bytes ...ters_1_14_R2$DataConverterMobSpawner.class | Bin 0 -> 2430 bytes ...erters_1_14_R2$DataConverterPotionId.class | Bin 0 -> 4579 bytes ...ers_1_14_R2$DataConverterPotionWater.class | Bin 0 -> 1855 bytes ...nverters_1_14_R2$DataConverterRiding.class | Bin 0 -> 1944 bytes ...nverters_1_14_R2$DataConverterSaddle.class | Bin 0 -> 1806 bytes ...verters_1_14_R2$DataConverterShulker.class | Bin 0 -> 1337 bytes ...1_14_R2$DataConverterShulkerBoxBlock.class | Bin 0 -> 1296 bytes ..._1_14_R2$DataConverterShulkerBoxItem.class | Bin 0 -> 2716 bytes ...ters_1_14_R2$DataConverterSignText$1.class | Bin 0 -> 2809 bytes ...erters_1_14_R2$DataConverterSignText.class | Bin 0 -> 3121 bytes ...erters_1_14_R2$DataConverterSkeleton.class | Bin 0 -> 1539 bytes ...erters_1_14_R2$DataConverterSpawnEgg.class | Bin 0 -> 3852 bytes ...ters_1_14_R2$DataConverterTileEntity.class | Bin 0 -> 2979 bytes ...onverters_1_14_R2$DataConverterTotem.class | Bin 0 -> 1308 bytes ...Converters_1_14_R2$DataConverterUUID.class | Bin 0 -> 1314 bytes ...aConverters_1_14_R2$DataConverterVBO.class | Bin 0 -> 1092 bytes ...nverters_1_14_R2$DataConverterZombie.class | Bin 0 -> 1945 bytes ...ters_1_14_R2$DataConverterZombieType.class | Bin 0 -> 1608 bytes ...DataConverters_1_14_R2$DataInspector.class | Bin 0 -> 411 bytes ...ers_1_14_R2$DataInspectorBlockEntity.class | Bin 0 -> 6385 bytes ...nverters_1_14_R2$DataInspectorChunks.class | Bin 0 -> 2574 bytes ...rs_1_14_R2$DataInspectorCommandBlock.class | Bin 0 -> 2286 bytes ...nverters_1_14_R2$DataInspectorEntity.class | Bin 0 -> 2660 bytes ..._14_R2$DataInspectorEntityPassengers.class | Bin 0 -> 2290 bytes ...Converters_1_14_R2$DataInspectorItem.class | Bin 0 -> 1306 bytes ...erters_1_14_R2$DataInspectorItemList.class | Bin 0 -> 1316 bytes ...ers_1_14_R2$DataInspectorLevelPlayer.class | Bin 0 -> 1770 bytes ...4_R2$DataInspectorMobSpawnerMinecart.class | Bin 0 -> 2478 bytes ..._1_14_R2$DataInspectorMobSpawnerMobs.class | Bin 0 -> 2680 bytes ...nverters_1_14_R2$DataInspectorPlayer.class | Bin 0 -> 1974 bytes ...s_1_14_R2$DataInspectorPlayerVehicle.class | Bin 0 -> 1943 bytes ...rters_1_14_R2$DataInspectorStructure.class | Bin 0 -> 2383 bytes ...nverters_1_14_R2$DataInspectorTagged.class | Bin 0 -> 1481 bytes ...rters_1_14_R2$DataInspectorVillagers.class | Bin 0 -> 2646 bytes .../DataConverters_1_14_R2$LegacyType.class | Bin 0 -> 3150 bytes ...aConverters_1_14_R2$WrappedDataFixer.class | Bin 0 -> 4454 bytes .../adapter/impl/DataConverters_1_14_R2.class | Bin 0 -> 26701 bytes .../adapter/impl/Spigot_v1_14_R1$1.class | Bin 959 -> 959 bytes .../bukkit/adapter/impl/Spigot_v1_14_R1.class | Bin 26084 -> 26195 bytes .../adapter/impl/Spigot_v1_14_R2$1.class | Bin 0 -> 959 bytes .../bukkit/adapter/impl/Spigot_v1_14_R2.class | Bin 0 -> 26948 bytes 59 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$1.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverter.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterArmorStand.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBanner.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBedBlock.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBedItem.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBook.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterCookedFish.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterDropChances.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEntity.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEquipment.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterGuardian.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHanging.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHealth.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHorse.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterLang.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMaterialId.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMinecart.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMobSpawner.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterPotionId.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterPotionWater.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterRiding.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSaddle.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterShulker.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterShulkerBoxBlock.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterShulkerBoxItem.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSignText$1.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSignText.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSkeleton.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSpawnEgg.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTileEntity.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTotem.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterUUID.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterVBO.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombie.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombieType.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspector.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorBlockEntity.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorChunks.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorCommandBlock.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntity.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntityPassengers.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorItem.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorItemList.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorLevelPlayer.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorMobSpawnerMinecart.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorMobSpawnerMobs.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorPlayer.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorPlayerVehicle.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorStructure.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorTagged.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorVillagers.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$LegacyType.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$WrappedDataFixer.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R2$1.class create mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R2.class diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$1.class new file mode 100644 index 0000000000000000000000000000000000000000..d438928631b9e8804309cbe459b8642c602b51b4 GIT binary patch literal 294 zcmbu4v1$TA5QhIT#xs|I*QZHg?Q+2)X+$sySOmd5z_E8XnDf?Mv%8viv+x1(P{Fac zbB6gp28RD<{{9a~0At)IND|x;(l5936@N5_36F0&>Y1~9_K|%k@**D>%jeNr?=@lY zZY$$LV^^OXzg?XmB}^-~QK5Z#{ZYTpo0{t;s&d!10$uB^_^4*HHR`hUFeg0Btz|zm wIs^`c?3|{Iwkx$L*IY%yTp~Rvf(KKCLQ&A-(XdU{kS5uUyPNoL9{d15O5E6! z;zhj7W8Mt&9&g@1Uf%%BaNr~GF(QmJVdvcP2cb=_Bw=SVT@d_4$yR7fc$_Syu&m0Z zNHl-4%n0o!tPSIE7T<;J=4!R#S){63H8Q=J{%xHQ+^a?>;yNz{;i&TxZMB`Fcq?*x zvf(ZFF(xb%RWVbXoj-#V*Vb9ftGZ;rA3FX<6GlJ!;X+EGqmmmV z4B@cTWhIvxyIpTY;_|rsp8=0R=(!&Ny}nBueZb)^ypDnYRrfG-7`RQs0Q=tH6RFLB AnE(I) literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterArmorStand.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterArmorStand.class new file mode 100644 index 0000000000000000000000000000000000000000..23243d52171e4782b9ca000bbd37eee1a6f9354a GIT binary patch literal 1352 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 Rob*8~V;oWH$TG5F`3GFBd=vlx literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBook.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBook.class new file mode 100644 index 0000000000000000000000000000000000000000..b71ed5642aa4f2b36329a1161c71304303b9a209 GIT binary patch literal 3369 zcmb_fTWl0n82(PXduF=~y)12YDIy}mmR^P;AhcY&+zO>YTUtS-&hAdPL$@=_%(UD@ zyx;}Ay#g-~6M`{5s0pP3BPJS5Au16ghG2{aV}cJPCM04a`k&pU-KDjZ*oQrr|NQs= zJO7zIfBW>O0OsHwFQ%Z@gP;e?y;y;jUaZ1u59-8bjR$MRTrY-oUNm667&dsY(Thej z3EpNgY?9F8MFCoK@FX@%*y6=gc-n(!By9Df4bO@}l@Jnh*o%p16^bH4uO=ZXp+kbs zz!&O2P!rWK255#3Qj-JP8@sS!0! zf{NZ1k0}|t?6#`5syS_qv!`W{g^3!5+^FUVdW&Y+x@jb0sAG`ANmm%Q2I>vXQMxFY zu%)&;imh4Xq|%erTBS79HaDx$pxG5SyNyUq>HV=YFbd6AzfJ8?m6&Qol_tm1jVQUs z&CoV2>|~yNP@+qef%8O`J1FWxSqvNkd*zl9HP6yo#Z6RN@1nQnJEb zafb0tjvDS0Kp=Wx$4^d^9;oB%JOfLtr%Q;#y?H zlFT7P4)usT>*;}^SG9B~iEgj9y<3eDDvQ!3QrEY13&S|lI_P0-I#;R%+;=OHJ5+nE zwrhQR^R77Ewc=rP)(O)RnNCK#WLTC_wSiO@aoPHAvQ-qQ8#WCyM$Y^uM~?-~m}yZn z3*D8gJ6RxydALKhmQi(FWF|=am}W$sj{gv#H>i0mLEfZC4RP5E>@d zF*maK{~?yX2Op*%!z1*8m`y)=N@+KZRtnAZ)WALS6xc_!$iibZazW&uU^=bkBm-t( zChZu?P)?%|uB2HAy9#jp1Dexi&!)+`24pJ|G9;U|3T}8v-4tI|nJ>E+u3oqgvk7HB z-V146xzCfI(~F$LjESYE7v6^Kd9ET?MK8v^i)$4{#4lI7SvB{K_q$2<2;TF%`;dDC z$NX;6mzO{F7z+JvahUIlBnU@QkviLR_u1Z~C^&A1=g8$>popKt6mqMS_hT+U zk45|fmh!LA$iK!x{tXWCZ*iPo!u$L?oa8^CkAIKT{0h$Ut2oDhLO=fz7x*u@$gklt z{|#68uei#u<7fUmZtxrUi~qs$c|R-WH`!!5RM)JRy!{>C!WEn#uV_(`=A xmav9_!RP%GCAY|Q7MT>#TSjICvR#Drb_C!hw6|j$7yn<{@e=LZP>9!&^Dp2kwygjF literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterCookedFish.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterCookedFish.class new file mode 100644 index 0000000000000000000000000000000000000000..86fcb22f2cdf4222114e19ad97ee99557f4ff6dc GIT binary patch literal 1576 zcmcIk>rN9v6#k}^Zd4f?pZ=x z|GD#293&ZhD~4&f4;XqP(JX^EWfcU&K$@&JYL&dOGdy1=O*n1oyqx8>A=fRX*WEE3 zhLI=SeDf(&Eyd_S&+`1yL|uEnh2@ zNbmx$5?nJX)w0&*(aALrKR?l>?hsKN{YBx*-K?-3!!jH3tT8Bh^H>b8BELz@#^X$e z7gJWHYSqj_GI}<1BGfBYhWJ@wp)Hr|rFC9y<SLiOoKkXxmrYpB}hkl*5?oOdD-{B73rp@ilL6s^s z97%Uhyye=4Sxl})Uor%!N1JPgsZ)%iCvjAU(+ugR`ovz1m+4Y<88j1=Y_K^Uw&_!x zoFtPEz=OZ5BF5;w3W4q;{g-7E(wpX`pBj`j=V+#pWF&iMj=YJ z4KR#Lw33cSX_VkNNeT82v9E7P9>;o*VZCka6|(d$>0x1mKg#`JF7FarVLA8D4H4FN%Kse zJnbo4PQR2n%hH`>p1ZCv@1``{ zRNalS@lExC?c}q1*6`F!abtr7&+-D{Rl_Xg)dO3)D~XlF$ja^Ez60)>lO`Bia=Ise zFYAtL*w$V~a}2UpCdP0-oU(LJH7PaC;j5nN>JCv>x5}F*)P_p_x z!WlwV#`AbCZ@3;qv@UdtVu`z7GYbqubwR597@C(nu5HZoLZu&}CA;Wo`ivnu)_tH> z)e;V^^DVAGK{K^^mRs4HD#}n5Ttq^_FfPd$Q80>51($I}!5GFF+NK=SuI;dls|-R$sOWQOj$qnq{?`HmgJL%aZ! zf7eX(B1kU~LlZqme)?$8$Z8=?CCNxOM8AN2CdG$VS|#C>9;1zPr5u1GI7$|gL?^8R zJV;W2{cW2cNz_7jYM}lq^fzG@FxiQ<``Usf_}^oY)W#A5^YIcI8g|hW_m?0w zz59TUc%Y&MDW(KD*4|hFO_5p!$-78YK?7A#PrRYJk+i=N!Q|K{L4PmheyS0qr)ZL% zp+kBOReFI@=_PJRuP`gU#zW~1o=9)^@`@sW4tlpw;3Q=|OP8^%Q9hMih1QKzlx+{4 fAi+2Klj3|hO_mR52o1E87DSX}h&mI+kQDq4mTQ_| literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEntity.class new file mode 100644 index 0000000000000000000000000000000000000000..235c934e500dbcdef0361eb73ed0b6e5a986ef58 GIT binary patch literal 5985 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 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEquipment.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEquipment.class new file mode 100644 index 0000000000000000000000000000000000000000..c2c5f8fa385b4e4c4d617bf07229cf7a237a84e8 GIT binary patch literal 2356 zcmcIl%}*Ow5dXbr<27dah{H#KG+*Sy#x`3hX+xZng29BuKmrCzOM=$+0vqgIXLq53 zbB{gs)=0fIQV%_(s$`TR^$%$Of?j*?HHS8;I?rB=jVjeuTUmZ@X5RbF{N~M!{o^0s z{{UbV8v*oU#E*9ZXu)Uz5^nnOu29~Sa7*YTVi^<5Z3%I4LY5ZX5tjG;8296@&_D2F z!jDM_32`tLKqsdCNJ_XTVOGL@2Hzds(4BDxPbj>?;7yo0jiEiI8`}JCA){GoHIpYx zFlA=d{EBMnLU)Z`XIr-!x~Eh}O_;`>W;vQQ{cKk+7Bs_QkY^1;vl4mLwl%u9n#!65 z#ooC!_DuQ2wDLJEr#nh!cV~w-HK!H{t>}efUa50vZwzk?k8UiET&*)#yo2pcjnY$xlYtF zbiQQnT3Icri(>ZIJ!JKLhn}i?s*HY|XK1cIuZ$GtWXxlMtoKwSH|uBxTgF2?VhAp^88Un0&7(FbfH z6676$5kb8VNQD-S-^fBS>q9@XyDho)Vf%2&~4A&_X6z$aFDQLhCBw+Pq&O z840$#!1xK!dkl;=RV80ll3Xbg>?pe;E+w3a1cMzE&G!YqBhgRX<|DzguJ4|Sc4=lw>a;Mm*AQjbgQho_kf8jI k`){yZ7IME)FL4SXdT%Ll2+W{gWVyJ2?|zlDGB zL0@8(W%&Vqlx0sYkQBa9>cdV?_w?yL-P5x_e|`G_U=3SwsF;i5W)!#LxQ+QZ7O)t_ zl2j5=B&A%IOG?2V1!)C3LuAvmO@E6am`D~GLOG`_7)JA^E%q9jc)#THVqI;(3Re!_3;@{_6aIxtAu(Fj5h|JSz&~c1FF?UL6)anfBi^7Hv zd~Q^q^Ln?R@dKyf8se!bJ3cc|?r9g&N4&{Zj9`=@+G_$sz$`1ss94241#2qq;{ikX z2{qYO@eu0_!)>L9P_cnWDzeyA@R*_SKdy#hOp?_tZddddr6XbZ4F7ZpsH%Z3F|1tV zq8VZ|ItRXM+7*VyME;C!$4HZK&NNU}4;vB34Q|P|&>y5zb2j;wAx??59mf*#VGKC+ zGLcivJ7crdAE@hdo{W665m(flCQZyA!;-_+-(4=|Fhsu=>NWjmg7neskv2v-hr vlsD~klbw*=bQByjxJC)DOOgo8hUxr9o9HYiNNS`HVFi~Fr{1jKZY1^_I4W-} literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHanging.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHanging.class new file mode 100644 index 0000000000000000000000000000000000000000..cbbc794e0891879c1a7cd40d93bcbce01de15b9f GIT binary patch literal 2209 zcmcIlT~ixX7=BKZoL$l_#T8K0T0d$egt86N+LnqmP$V`$g%n$=g~MhOmh4B^Z0ImL z{sM2D@ut1d%T8yUsoq3KM}L4nNu7@GNft^hmT}aXP2P|5em?Jec7J{J<1YZlu$9CM zcw5E!Brf2hit!{a;T;tdD&CcbCE-I>|FA zX1gGU+k*wq3JsT9G6PW#jk*<3sm69YaMqa56^o)W<-0Y%;g!bI|ID1>nB_Ixk{wuP z*ec-kApx$C`Sh+ibr3V%8pFsTUVo{Qff1;BVN+}i!y(L#r7$4eDPFwn2*RJOFeD_K zr4pAyVOHlvtu;9XA1b)PkX-T`foaXya>6fm;JXL=h)kg2C7fV5VwV)$)UbkE4C*yu zdm&|{Xc|7k#|&Nh&~j%2;Zit0BTPEfa2u<1ve&PMH3-VCVI3wFSfu16lwfHnBc-8& zjYv(IY@{M#MZ=~%uELS4MTr*uP)NWvxR7I~6dHV_6cCzA|HHB|^gKp;VSSV4&G4UY zH4Um`3LP2S^JU09eVaSBi(&Zb)}32LgQDBCnRMD)ht%h)D9sBlsv=JIl z(;8|UqJGudStu8GYP1{u`^}=Y%}YClvgdX}GUxbMGO3?23 zpbR3o`~bdL4--w@gFdTXC+Y|r&g47Od_Cx}xL;OC5f zq>0#^9v^NZF`;uw&c#pMgW4Cri?1`f(qlHE-ouv}y{pCEg+pu;$scg^Vj`n!^fYm7 zAkjqkS`)`JdJjF3=9#ue&**xjdA6;g0KGCpHlz1NVN=A?Ly;33Uo_EwAH5mFZjKIINR=PthD zH9X*3c*sNi#P75Kn}vc&dWohngajTyk2nG<0#R}q3=@nBnlynCg1s9LX^>~AmVVqv zmbf@ZskVN^AK|2ew;1~!pZ$Rz1!KSAD0!T1jq4m3grc-+TSGe)Ic3KmQ8gIKGTy z08>pkifMrham?UiGoHY#fT6R0WZez zatyD;@TvyQ($G3}&04mMa_G2*X@^4^noK9>Sz$S_HFVUU4p*11<>d@B3>+^vG(ru1 z*zufjL_M2q@Sg3>y+c!7s`dS9n4v2mpgLG&sgrf6*y{L+iVQ;PDw-iSu3=X zzPD@#p&d-vmK)|ZBqlx24w9}_D%lj8o67hFqqKBt@Vc?$2X5BRI-!v+FD;Q+S*u7@ z!zmP9qt04sVPIk4_`>Y5!*$!$OX&ZmoE@r@c{?aMzE_E3QbR0Lbw|V1t|`wBjRFJ8 z1lD3`l}7|#?@gSQSmb|<7iS7Z4gL43-eQJUW@*|g z)^aL_Gj6RUanmmc8GFo81=w8||LwH&s}@M$Bu*vp5RPkzIN2CpPv8x_8N*u%yp4A> zL{+}V5_lKyCGb8zNZ>I9vhWMGF;0N^3%QC=GE2ODW*SbM} z;z?`SHj7Ty4w&v_-pMT4D*Z`+MXdwdE~=B}a~>tm23AfLM^sh?i)>Ssbwb*rQ0RoK z6Mj(QDmtFGO6sO@$MQ(Uc-acFm@>bHjFhN;h0|aug(9 z_6uo;g8HnLPCLq=nWtCu&ditHCFNb*bX+#WqElkS3UkSJ?NIp{t=$nbJ%43d-K?*N z8a1z%9cDw!JFaWxl$DlscHDRE0<|wWVTK0dqLBbr5Oj?7DM0b>F$gJL@JMtH5_2 zT8_sAZ{2948uC#0WzHdX(|LP!W^rz{$ZpuSQLHuyCzYI_KVz=1dc4k5O{SYqTo3Gm zzf2={72x<3rQ0^{cF&j^vHMiDbH1N*ZG&vV_eflq6;eZ-fy6y~Wx^`uxzfbOoH5)PBxjInq|u%qpnY2r zd4#B|O}zs{v{aMl2_o5wnM)lk!p}FW~xzcGE-66YNmAAW~O3t zvzZc7nyEHjwi9D=3sK0e#3s3o7?<0L&2k4ZA$Jm6>}=w-Ne1JhqzDn68FnK;sJSt rcu@A6Kf?GP5!DphhRPmfq8{g71m`hAD#;ziOL!D<_S;K%O>g=al|E!3 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHorse.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHorse.class new file mode 100644 index 0000000000000000000000000000000000000000..3b5b9119d800771f66066e76be029e1c0ff7c63b GIT binary patch literal 1602 zcmb_cTTc@~6#k|you!n5Rq(EO!*X3wM39S0@j@&ZZ9}4ol4(2ErQ6-IyT$NRd@=FC zOO!;628|{fU;RnM7|(1g(%=h`O=iwFXU=!#oH=Lb$FI*{0Sw|s1g+@Qa9Tqmf-ZDN z(1TtLeQMFKL09sOh5-#{HJsBhs1)ZpE^rKUj4*`949oB)7=nqeIfhWu&P#@tlwrx) zN+~OyjL4d#iKpzGFz1A0sC7*l@*Wv3?M(?!ByDR+I-YcH*p5qt=(J@?Cus`Tm1L7n zPjYiUT#mUKQhPv~EbvbWbMgM|W5>dplo1y8d zlqg=%`j_VA!cf5`attunk6jnjMm0gfIk6}mKg`v6bDj9mW(-jPj z)MshWF{}bZXCn1C+^Uk=W{avWt3TYZT&xI_euuWrPO3SNcHN_z&_UA{HK1YndKpTHWukIUM<||0@x46kyG0Wd$j(@;i z{t<$ILY{wt$-lzk-~IeLd_VVbl&&~HUcFkT3LT@E8BUNk2L2PnEJ7b&M*~@&By9kv Vu%Bd{Pz#2z4-qQR5H5xre*@zhlZ^lX literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterLang.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterLang.class new file mode 100644 index 0000000000000000000000000000000000000000..220c399c7fb3a8a3aa250d9186762eac093a4191 GIT binary patch literal 1393 zcmb_c-%k@k5dM}Py=yssRly&Kpdz$@J&LFxh6hVbh$l7B@Zf`FdtKn@^{(DsA^a)+ z4?d_5HSvMO2Tk;kGR|HLw1F2Q$=%M*?0hrd&d%7 z`*@JV1RhFtQbk%tM#VHk{Dtk>;R-`6o!Meg@?Kdm^qaOT*6Y=h@Qb|UkR@e$7I(I| zZ%e&pRKh(wU>IEGAthBQx;`A zG)nbKg#<728UYQvT62t!SiyE~JGZdCF+b5^mMNAQ`gTPq?OVbRY|oAMu*RTTO)3oU z)21szqe`2xe7+MJf$)i>anOvKGuB@gi+nflRcl_|EiY#-=S~T&YK&`Y1)>kN!yBblBy^4 zOz)6x2M-8*lDHjqVd6w^#&+rgw&%&p8@=*>=Z|q{^qepx>1~P8PYp;~FU<^+jAZxp zH?S`>=|UfkacR_!(NA;fN)8ynHIfY1F+`&TXGzL6WiU4PiDWzWM;lf-#SY^}3tNUl z{=nEws%t=NAodYMG^MWri#6 zh#50$T6NV`*R)2==&Gx(x@KL&%C4_&)$QrJ!28~}-+S+$IlrlR>g1~1&;I+tM=Z-4 z%5ICm1UMdHNd%&>)cxaxVLZfK6c0fHA&F3nP=`>DkV067(14Ie$RK19atL{Z

3Y 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 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMinecart.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMinecart.class new file mode 100644 index 0000000000000000000000000000000000000000..8e4f1bac7d36df22aa9ad89877e812341444f74b GIT binary patch literal 2029 zcmcIl-BTM?6#v~Mn_a>JVeJRD#bQNC0NGNDZ3WR1M9@H$jc8geUN+ZsVY8d=ZeZ$v z;)@SH`(SkjZD-o?x#Nrv>gbHl_;>iAlMcKHi8r#GiBZmwS#?Gm@Ip&0tBB9dntA_yJdi(^?~Q0*ophMT#fCnB>Z zkp=vN$P7h5V9nj8=V^0op;Y44f?uoq4X-krKbkt#gTgZoCzuW#`Up$XuGJZ)j_SA1 zinzVA%Ik5$sYw{LIooZOEMxhNz!po6EYRt$>>MO*N;Zj(VLU;m?VK?roQjHd9TrMD z-U3xV+df=(Dxz8QROwD#=y)6N=y)8bRFrjG$C!>Ac$W;~_Uq^;9q-|$j!nGJ(AV}> zxFterg@N{dsS$YGCcM3ENolRrac6SKQuf-=R>M&k_@HQO6R>T#{@R~3+!0u)h*A5 zvC6rW4n)o0CFlPLh7``q+E;zQ>I#$Cn(q;DU8+_*94SuS6MI*KfZvhBl3_e|qvNV} z+)YtDQx9}$!p#4>&cX;y`;%Z8qVJS^OGHo8k0OCHND-yyNs_a~nM4^;W&BI9yRpg$ zt!XJ#zQL2k>rDlm!_%~*l4FckY5XivX`IY%e@Y~Q5n7w3-*%WL4@`5&w@mLN86#OV z5)(#pAE|vPAK{XbUY#)1eQ5K;ALGpM=jgeI48teL5<7eky$O5`oph3u`{;{R`zJn= z5aPSfK_l4Tpg@pF+r$@h)z;4N%FJU z!Ya9`I6LP_sw43`W>ieG--y?6;UIs@aTLJ$toi_YIccP=a>^L6%8HS-%4uWJDyxQJ xl{MortDH?6$E>e#{0sERRI`qJJt7>>kt{(!^HHJ(aVM~fr;s6ht9Ucr^Cw4r4J-fv literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMobSpawner.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMobSpawner.class new file mode 100644 index 0000000000000000000000000000000000000000..85b147b39bb0ad2eb5ed274f2fb175e4717f3eef GIT binary patch literal 2430 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 Xj)=(M1WC0|Bah=qk)FpN-97&UJ}>eD literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterRiding.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterRiding.class new file mode 100644 index 0000000000000000000000000000000000000000..39e7cef82c1a75ae19713aaf8e05da07d4132665 GIT binary patch literal 1944 zcmb_c+inv_82%`} znwDHxZI-1|66FTnB#U-MG?s;9s_*bJ>fJM4hHaOGCknQ;CLK>Yi)PidY7F|EWl5*d z5UwjpsZ^}kO~b99Is3qPXgiInteT!tUai+@6IIb7Q^Rbw8b+5lcO|!yn_gKweyHm@ z0Le2XYSL4ZW$C!4ZTWG`F=&;54#S;P(UP9gq<|`pxa%3Nbcm?27WmB>3$vw?s1@vH z%U-pr`H9}tDOXn6^F)oJ^Bv?Erh0V|sWe**152K$)aOMj%MaKnP)G>>KhD!{KKfd=EhEymAf|mpq52G(R_Sn?^=ds|-6f zii3dizSNZzS$U&0H2!vf%nDa-W}f9h=dO47-oovGXOd$7Oh(1&fba&^gn!*)9BfdY15Cw(#O!fslX z@f7XKI690cuW8?C`*eeCv|~Gl@zC}$BJ>0HWRiVD@irpAVtYE%Msz-%$+od2Tm1dg z$IKhji1>_l6DROz=;zNd%wJ%Xzr-&73gi3_A88-y4I_r1u!ne%-w;!s_R^nG5{N0u z#%QJa4SCebE=rQof530Ohqf?DBw{zS$*q%Z#BZ*rB&pQ+YsC1UNbtWf!r%D7>A<`L zH;My39Jvh1#3=6vamWXv*CPbJK~z)%1}On;^w0a7o>dVCc}yrVe+!Mj!vJr0q9l_J g*kA~zbt3P>5#Pg6f(KQpk4is{5yZ)A8fW;{&v*yt6#xJL literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSaddle.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSaddle.class new file mode 100644 index 0000000000000000000000000000000000000000..dcad57ecf494ad75436728700a3fd36b9951c59f GIT binary patch literal 1806 zcmb_d?M@Rx6g@*>cUf1(_4`}#3ut96qJk)D3reLFr4^$;B-3^*E8X3?JH_xQ`V9Wi zAJ#+@AHY{KG2Uq_(tuH-X*zf2_MAKC-nldV`u)=v0Hatmu^&SQ;sz2XOk6ZE49CDF zwMZHmQTDQqQDq5tMcJzct|>caU|iYjYM4;N4IPs@Zt1wqpxtnNS57j-1_l=yy3;{f zFzn8{zR1_!ZGr?}+lz+V-i6k(p1%Zg!Td|!m= zDvu&TphC73cuur3HvZCi6@=BYD7(@r)>l@@@G`Fv)p5OA)#->9EhU$dqe}}TXFJ@j zO(qz2RfJT(EQ&C41HYL^hCwg2CYAbHi$)ySfUP%XD zEvWnDiNWo`saAebN?xJtngNmw!`lrJD|t1Boq5SiD|5WouCAF6>S0OTbyYQwcBH>v zmEjkBm0LK7Lkv5ned)@znIMda(B+mbq>$DzWnmh38O&DEGE#UJ?qP-wzvZ!z!F`6r zcIw2?w_eigQS-4=g;yf`vQ^Ivz1B{QrI+QK}wJ zmHQQEzW73vB*TC0J36I~gJ9^T2F%OQ^(zeL2eQBRZ#k)-Hn}=v{^V-nWt~^)qU_%o zq?N?P;8VI!%RHJDYxBUGeGm0FX(**&Eoh6=nKgjD#g6y_BsMi_?TR@?ru1yei{e{)BhIO@Mpc)=B12jHRaUq;3&Ic%HlsvGz;&!Zo?gn~ZBOSN3KC=P+4aVZO z(LnEOIG1xA*pHj=z43QSPBVpm7?i>c`n3#( zv{{U3S&VCQxUJH TtWC3hxQXNRcXfd59j*5VQjXV- literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterShulker.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterShulker.class new file mode 100644 index 0000000000000000000000000000000000000000..9239eeeb8cad68b628d8a0b3ec9e744528d7f819 GIT binary patch literal 1337 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 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSignText.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSignText.class new file mode 100644 index 0000000000000000000000000000000000000000..33eb0d1143d8f6d6d89a6e074ff9b66a15e61447 GIT binary patch literal 3121 zcmcImTW=Fb6#gc0vL1Ia!8AY;T5bX2BxXrSTZn0Zn42L4ibD#4Camqj*<`(IcGn4) z0=*!izVJkaKvn5mALv7Ar35t+s#K&({ZFlWX6*!gd;c_!Z92VA{oMFoCxA%5CcJ+3SuyX(>NnnKa#^)1*s5LV~Eqf za|(t-_!#GdxS(Jpgp0T&hfm}%D%FlDxEw+=`W5IQY(&4Dq~(xNAQW6tkYi{(tb2OG zwx)#R2`6RbtRZpDV^EWpC7gt*yRL8$AW(XwgtYBC@U|3?Xm`@95NKc!@i452o-5k~(L(a?0fH!WCfni^{JGpn?Rc+dK z%&f>7o|Z07P7=|xdV$bsM!sNbRe;^GuCcD3v9sN+RqXk55V&wocyeu6IIdw^KFB14 zk|~{;VYF?)5}uYPv>8Xg;%TmM$Q#;JNpqJr*grI+=Mr|lU>B`yJi4;&WH6I2Fzi~X z*s7GLXC_bSg|ed(E5tc4p-<_WsarWMpuBTyf-DMie~C zLj~95{u>fC4cl>3#izJME_+>87FmDMpo(y)OyugDu98-A@on5u@fki>@CC!r|6zrp z;Z;VKQi$P=Rz1V2s(h=mSgHYr&gCOpUF-~;+Q+=;j<&^h5?#!qsu5RGcUrC-xBU(2MWJ~OU6hp0FMZOLeY=BBW6-uOQVQ1S0t-mFaO z!-CqMp_|4HnQnt^OZWW6hpyoGmqvV~(lh0wGaOhR!Q#4Vm7r1;kixGsj#m13-aG%& zY!}<1n}QUr6dhd#uX4IBzq}6dFtp- zy`DHx`qGF}mqcCrEZ8&ps6ji8^^(aCqJzHG(gt)QMl;G=Uq}kaXeNbg8^jMpDn%0& zqO}X6yU|4gQuG#TX+O{zsp*K+&LA*@x<}a5-Vv#vg+e4)BD_RGL^^(yrhItK1Q7ff z!u&WIc@i7>32fsh(ar~byX#82%XY~My0M2W_xKuEJ1x^KR)WHwA|Tb_Wk)CB7-YSH z$XhXj^BCX6o^#l!bSbZTji-z97_t1aB znph+fc#gHbfu_Lk2+P&T+vVlD-a4O2w${n*74!8K^Oj1Ll^Qxan*zTg@*Epx(DaNP zbe=BUX*AL$au@fA-p2zxBwBLaDAtqf&Z3^D!1*~e@nM|g^mOGT$nuLY_$7G!GN$<` zuJbf*^DOT29PV*}ulNM+a}y7^jfXssN8G`;+{IHqjTwFezww*C`+NK(d%58Lmw4ZI zKlvCRU@v*U9xt$uzG}fShhD@f1~NFCp#F(&1^X3zxIt~9*K!{_wJ@v+A&3JDx!X%Z z^4C0v<_oiEiA3hGkv`s;!Miiq^fT7Tgl2xmgvk{67OdrcbmT1r;UKNm;1F7gZY52d Yk;OL1x4HZUiI>HAJ*NkJ1lPg;1_1jx9{>OV literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSkeleton.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSkeleton.class new file mode 100644 index 0000000000000000000000000000000000000000..859b5c2505ff39daff05b10f0ebc21bbbcbf06be GIT binary patch literal 1539 zcmcIkOHUI~6#i~sw=Kh~il~61AW$A13#hzArD#G@Fp;JvE+CibwG5p{nVHt`Q{1t0 z<3cwjG0`93PcqSXrVpUO4N(^}=bkg?JCE<2x!-?%`37Jf&*SLCSQO)NOduJ>WE@kN zj$+2wQ&FhCydOo{m$Mx691l1iGDKE%OZQe8f)mL+LnvbxBtv&rx8zpE+>=gD>=|T9 zWNl3tdEw~3-ZX~1ecff~TNj?l*j80Ko^-ZL(vY5QF(@0BC7p~RTvw7?KC9WL>XsH3 z57l?JV-#dT_td>gsYF5)M47;`Y`W>8U0)r8(lQr@GRiV%2IRa$4P5%jHBdW1D5WVilH?mvd)eIz5y! zsF`Jk)TQCXP9l3CszNn{RaCbo;(5jOospx^p5yOzJn`tRvHetihj}pmS*p9mkU*E@z7)hoey5j}h#{rmufyo7OXV49nByOy!U z-Fi)vl(!!v7{pMWjFo0}R10q5Hq}R0F@|x6`ngLPIuZOyfiS|99|)6il#Bt~!!?o# RIw_b#AL7LB93DktzX3v}hnfHY literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSpawnEgg.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSpawnEgg.class new file mode 100644 index 0000000000000000000000000000000000000000..b24b8aa19afead21a35faf7c8c7e097064b636f9 GIT binary patch literal 3852 zcmb`JX?PSx8pr>Yq%t+hgoJ{C918BTLI^Mfkt@hCAqiO$l4VAMAcUTo&PO@lBJjSz2LeY0jtLwW_)y>@fsX|~5%^T#Gl92EB-C%4o!nWb0!cpI|oK!tS>3qwv`~?iflWJCyY=fIL87f;X$6TJz#7!?| z#BExUt!~1wR~nwB<^zi*e%d0-)k_TDXmFiPrstbpG;8!ajj0qvsKs$iufaBQIg`Xz zwkF(6IM*|0?#6Jh>)A;&Y5C!JzNd#^B#kU7hpkN34xeW)*Hzb5H?wQSj0xv04{k#- z3`v>3dbiT_a+d4pSXvkYiGoWE>n622rXS8wPzlfI_QN^TBWJ^#3YP1_%OkOvk!o-= zSvT(_>uWAgoPkkz@>1!obmG2mq$qH0xsGAl<=Vc$#0;ugF70~$blNsbu_iKEhKi_f zBzoG6tgcJ|zhV&c6ZSxD%c5@HOPEcTs^pmS(s(Aj(^PYWa3fYztDMQyyqv0L7j+Or zk(DIFA^aM@3E?DuOM6pjA^Z-%X9zYrzUB8(7RkRQM#e~)A^ZV<4B=1sa|oSS6~Za} zC4|4?Zz230|6r)PupO!WT6{CZz*lv&dvP)vOMC7>GX+~sBbQ$0xITr}VOX@CLwoVX z9*NLW)Ny;`hHcZZ$@0v?up*kFrL*&@0fSD`^s=Vmk#tpKpV{8ss8*s@$}wmuRFLX$ zecer!14^5-5!d%s3WLhcCeO&wxV+Qy)1=#zS9=FLJS$@+V-9&)-b8zolTpJ-(jie^ zP}}$9R=9~C(=X(Uq+(V!YbFQ6sEB6Ggzp*lnRz;I_n2OUtea$W$P&*;xz5>$$`*SW z*Q4sIJxU_3K|)n+s?iP4UtuN9!tt#bTxv+0ITEQHoHyk?$4IC+23KOsW38JgR#jRG*T9|Y&y=}RxVA75!={8 z27;~B&jZHFwPGQ4q+6(1#LdyEEsm&+aau}{GIcSzm9cy>Ae!@rmn8QnhG?M*Bu?%q zC({%Y%^Fne1sc*8Rg~m-bYtF9b?9{MZk5t}jvCm_6vR}AwkdO^?ORM+^>M{Y%eLvH zc+IY@`kwq$hiIwm<;a236-GR6k(d}1qt?_8Hh6tG->?JtCqs&wi(_U>3;mI^=O65F;Y?}E9rF;BdN z(8VFEZ+bClF~lz=|6fxcF>>br@;TIU)TzqBLadhxBC6b3@c%U|#?vpi8$drN=x?<8 zu+Xo+68fVr7p<(JQJBbxeDYzi12ibYP4p~Pi#(3CG!7L6unq>zC_6~dQz=g+D&^uT zYcJtkRr4Ix;xnpAm<3f9Krw9sbjzYzS=^73e(;^Ru~wG$(}g%i3c~VQ8SF>dtdgm+ zxQZ6acVWswgsMx1;`A*u=J8SdbBv*Pqj*0mNM&k2hIEpJDT>u4J5fdk$aZDze&wVN zY!)ggFbhNY22}GNjO8{aa0g-TqMmQWBJN=+&!L0+Sj9JEE$>5;->joqKpxlQN^~Oy zj%u_c4U3{4i>25=qhd_JBJ{x4Iqn{anqowT-ZD7kMJ0;9!>RyW`p^E2atLGxi&5M{ zCg@+$)k7JMqUsPr6mE$e8YOTk6{-Sqn5K}!HG{HRvrLZAESDoSL-GpE3OP!1h#ak1 zDaUA5$+4P4<&~OJUZpuqj?)}2$7@#0t2IZ+A83x0Kh(TJPS6}Bf228DUZZ)HoTynN zCuvTWHJY_@vgQ<7t2tFp(VQlyYKG-B%}Fw>IbBZItdn(`Gvo}-Yvr|?Gv!Rp>*RHs zv*awz*>bk#963jGuAHkmPtMbYpqbx` zc77i^`TgkP4V0JJHd~zll*;lihsbq;z!xn{22R&A7|h457}w{QBi<@TvW+FDH_Q?EgH{1qf@z2 Yog{czPn0x@;RL!+Mt9)}{IWFoA4!D=FaQ7m literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTileEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTileEntity.class new file mode 100644 index 0000000000000000000000000000000000000000..33fbe7db021078e3d8430cbeb5da2e63b8c4de96 GIT binary patch literal 2979 zcmcImS#T6p6g@A?yq94RXqE^FL`6s-WDJ4^5>c`Nnm{Bm;Kul-r!(nHPxsK>lOf{1 z;))yYE1#BCZdE9jW$~qj<%gwJe7Gy_EB>qH?U_!xhgeooYE8|&KBw>Y?!E86dFRj9 z-vqD<`=eNci)+w=L4j>iY{w;2a49b1xZDF*M6m-2fhz^1$0r3;fs}wIFeH!`7#7e4 zMg%efhCo)p6tDzx0y_n40Y|_U$P0`L6a;n&j0s#Nuv_42folY=6}V2|dVw1RZWOpl z;AVka1a1|$O<<3}?E-fQ+$nIEz}*7(aNNsrAIJR+OfpRC8Ihwho_BR4-Yavh3^o0F z+LUhI))-cozilf)Lz?M$ziaDex^*(Mj%-BQbW?ZNF;vz!3^G)8SShkLtw%St&G~Fn zvj=3-AV%r2RA~%KTlcU}R=LBv!%*8PUD;uoqnhoKf^KMCrmMSS46#k7so5QdbR3NY zxA&-4Htu9v*6fTIEZazFDcy}H^O+1SG9`1Q9@n!uBVK0FNi-*#S0%QtTwF#6j%Xhz zr8U=kJE+-?ZkfgXY+~SQDJ+H^^*yHM#;>BY7RbxI76;c<>9Vt5iyQJ1aP z?VM%1(qNc1k-oK>nM#!C7@o#6)Jg5qD>fMngpxiLY1brGqWqmti4K`JQnvTDHl%55 z1?t*_<4QBdP~9=CIW9G3Afc9+s8=y*OV=XTq4=oNCTLF0>Dm@;Amo7rvSd4vG%Pj4 z5bf;g)Lcz1+L<4?Ny#xoPY=6^)WlofXZy<(ce?3e8WB!?X{BqIaw%{HxxnEN+z6fzPdN>=qkg^U>m08YJPen zeY)cw*8w@7ifz?Y%TDzfa_qRIj^s01(%MCH$s2Wa$^+X@k*My^qKhJ6`vy0bA0!4Mm;Oot$RUc;I-JVUYUde;8S1=Wa`Kgc^_GKOK)WLCVGg zL*t1IKsxv|QcHIS!;<>RBdTFCMLx?eDVmC8*7`F({zPY=JFJ3OW3O) zSIFx>1;6g!wF>I!@5vf4tflWfZ(`GWF8zI}z&cdXN`su3_4E{{mC;(g>{YOriX!dw z8}Uef7#;K+D+!fAeazt>U;#f;bWv9_4!}y~tN^T1RtMm0<(v}mT7?zsGK9HQm$wn& zA7Uo|2zC5ptl*zuE&mi7_-7d4pF{F5VDc}qn;*p<{uTD|ud$zhgBSR>c!Ph3!~A<3 z;XmLg{}IRdPxyoX%%c1kR?B~7i}^9u%zvXg_LI*F44|7`k($2% DSF1Gw literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTotem.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTotem.class new file mode 100644 index 0000000000000000000000000000000000000000..5f604673c8cac309a845ce7294019101e2cda940 GIT binary patch literal 1308 zcmb_c-EI;=6#fP%yKE_K(W18gTU#iVk;;XN>4g}RCRn31y)aQS>`rmZ{?Of_#z*lT zywIDPc;N$hW8#G-K8*1!U<>xDvDxgLnRCu}{%5}a{`>_%1r-A+T+(q_#}xxtam~PW z+|aQY9d2q^){xgwU`Rf&JzK3a#Pfx1hD6P`B*S#w_T*;IZOLFuv>f7O>%J+RZ4ubf zdB{wt*LFyOGO*ND-J5NM+SV^Pd z_X1Nswxe1vjOBV*g3_+o7iml)O$|EC=)M}%J7!xNifOFkmWEOq9Jd+f|50oDJ55US zt?jkbC}T~-9foJ8-Wi6OC|2$Wug#yfcBQEpPIUknrpAiIuzHd{Go)y88Y-YdFf8Tk zN8t{bGziC7V_E&hCgomFI5gmMqeccfR|_x5QF!ENc~ocU=(wNg9T z!Gm7V^56sbP?kN}2&BYAN~(6Jf40AGx_f%(=dbTS0IXpxi6P7m;cgQ5a9=HRNj$(q zr9INIpkq$Z;={Y=TK70P2fAD;}F6&mvYwc!} zgs6)a0lDS0Y~I5a92O6YYlpk5^F400#X7@iLx#$KApOAd+)fQ;2HlKOVR)CVxH9Ap z6=VA1DCB|kDM@}Bu@?FE%W73LN}kj5+HQS4*IzhoXgV#1Lcg$)y-=9V*P_+!V{*@H z`=)$lsZP)IlzP#D!ihK)29g-2Q&J7kku$J_yn$t`=qMQAcw(T4RUJj|pSQ$ooYG+vP=lE#ojzzE~&vuTgXD#YvCR@48crWxVx3ON%y=6$y z;6ygV;x$3Jzi~8e9j+UEk!6Bm;hNBB!^=qZFK+zb31SX9 z-2qfBT?jFHX>`akNaG|K$-$+sU|&cXzzD6Ha%w4zl5Ru+7(<#Yh6&uFRe@JXDsU`i ze%6PY6?G?_QI)keiD7LD s)7ngjI}_o%+{A=QOcDE?4vJ0F=jl#TGZ-hCCR@imQdE3`WL8W322RRQZvX%Q literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterVBO.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterVBO.class new file mode 100644 index 0000000000000000000000000000000000000000..3d261780418a5f51f734b8f17734526e2d1d2be9 GIT binary patch literal 1092 zcmb_b$!-%t5Pj`!?7`Uv2uoN31mY0nmQfBMBOg2nDUuZnV)=;GGt-!fXE8lJ=BGHo z1tbo90Dr^jGJZbn7D=82JRZzHE@ri z^umvP-D1es4*CoQJN6{QM#qojNg6s*^@J0U#p=Ya2>L?#nLalb^m{*H*nBCpu;XYV zm6odC?lM%5qev<{5J@7*<8{Z4L!OMDJ^#Qz#wzfn=WFhyqY;7d#F%*8561yt3Y82R zgT~R|&C|UlGi7KptPiEm%zdd6KaQpy95Wd1tPqB`wN4~852+PbiFcYOQc;O~G7H+^ zC+%KO4DC1^$7$p>4_0%hgl;%ysIN*hPvca%@|B<6>&{YVi-zlGVj`+2qe3G}6WMoS z8je<}H1ME`Jv=nkzL1c^CE7D*7)?}3 zuFf2=hE38KwqVhok?VvRxv<54eIh*1ZJpy57Tn9YGUv9bkQ{N$Ln~+HzoKyXc@e?P qPK-9nhCPk4J@cGLAr7u$o8shfZOXZh4ML0bBJN|CK!zX literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombie.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombie.class new file mode 100644 index 0000000000000000000000000000000000000000..7d2353f6ff3bc274d6e54418ee249ef664e1354e GIT binary patch literal 1945 zcmb_cT~`}L7=9*%Oh^|RwooikOKEHasac^^DHN=vMI$L-h}5E$Gi(OBWwV>^Zm|6+ z=#9r4Z@lp1oN$hw;}7uHc;$r`>N~p$5)U^Vd$IG*y!*VL&pY$mUqAl}UZM7qr;oOJ+(bGvt6Ffbf}{slz-oz4Ah@Z>G_uH zgmqB8+>Fv;_&i&3WMI^&Ak!1Of#FM!5;YDYzf;EQQl%pH3U00LHk|7G#M$7~T8lmk z*=5%14EeK~_ihBj+Mv-J&S9;Wj)|E?bI_k&b>Gw<)hU z)^G{K#BH03m{sLi(NMxej#Uk7SZ7ET{Y}fZ#h&yue1tM-B7Eg#U251sg;;MR);)Ju z`l`bkKE|eo4Dt-a;Xv8K*)z%wC$MVr!3$H?gAg`^*EBprUc)DNtYHhEGNk`IfgGPP zlwbX1v_pltt?fLMX29@DCy=4Hg8_z{XPGmG9-7>Zz_Xk^hU?krZieYbN*cs}yW3KA zRMoak$mb1V(+wLu=_IOoeqxJgr9exrYfC}bqXX2AL?G>{@K@x^wOz$N!^M-nTCk#W zmLO+Ehnjh+BX#o}`65Cj{1)_dXY|@6JXv!ODBP*e2(bA7CIe&iIu3%$p>G&8k@V7b z(?{2XG$XV#NHV3JJOcZHHZhFSnovqUfXlSkA^={;RXQ<@;~K5XI8Ra;$NSkI-;q3N zJ9NS}er%h;8!g-4(SCjPs?t2PnU=9oDrGTomX(|YO1Velj z~g;1wM{Negg%b#X8U75zpfZp9)JEBl`?);W}fEz-p>g)x%qJb-0f NL5hZD86PHk{sH}N%bNfI literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombieType.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombieType.class new file mode 100644 index 0000000000000000000000000000000000000000..1a85224ffe8a292af6cd4f70fd45d46b761adc95 GIT binary patch literal 1608 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 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorCommandBlock.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorCommandBlock.class new file mode 100644 index 0000000000000000000000000000000000000000..0e39e6c86f35d7c4092c0c96fa8bcfbd4c9ee86b GIT binary patch literal 2286 zcmcIm-FDkV5dPMGvQ?#ZLYorWP$+3@JHd*Y00~Z0V>bm8CxON%(B6cNycpH8T%D{od!0QIH29uNnu)q^b9aXaj*Hs0i2NwGSeu4^jHs_#+kqzZTY z;oqG3S69SEbNVqbe3g4i7B(x525(WQUBBlwOSM}5bO$J3cBjiwJngYe==TC!?1+GY z)fh682Q48Zd2Cy9yS>4?QF=9e#ITkdHDOjs-D~W-d4|g9SPc4hMBpw}9>b;Kw^V${ z_ql-!n4}tQoUBm|6$4e=G4LABGZg-Ry%G!a4&5w@DEc7F~t{5bMBdI9)!qw~}w8gJ2ibsY5Sq94?(p*4<}8cU?P zNYV;P>e<=CW5fy*@h3?9hUCwriQ#oxb=sjXA)zm0ie#g2jW;k&62qIgGC=wsNhCCi@0|`$!^(d~~cpPh*(HW!kS&Bw6|vxkTx?PBOA-N^ue8l=@65VzWH; ECmE}Od;kCd literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntity.class new file mode 100644 index 0000000000000000000000000000000000000000..04d019739c76e9a13f4d72d1279ae8210bd73e00 GIT binary patch literal 2660 zcmb_e&r=*l6#jbl$IK2BA)64h36YKD2OE-%AjSkDNg#XG)74?+bjdSGn<(K zic$}$^5n^j2jWR{;NZa+t1x=-W~C~nR%vOK7qzrXJ@_xAqOW&Ah@qsARP9c8zwY7+2;V-;p(Wz(;ANIIED@lopL;`;Tbu0X*i+dBu;7Q*3gr{R-D#wrUqy6 ztlWPtfh>A;^dTpg=XCUAK*jSaUQltKfpLc2IoB(iyuz(y-+kUa@w|0nVt+$+1@h#zpLKpq&lgjX2!Q&LJEIt8N4@?pQiXPgmHB*aIto#D_0M^Y>u zxM@%LZfRPiL!;?2*Gp#uQ6{PpiX}SIuf3t-RRbfqY=C1_g=IisOa+0B!!|I1Nfjjn zWjGAyA3g&a>Xz9sFgigM!0=F+PFcN=`3wiwL-YF_4C%^HLlj!71BUMA2N}KY(lExk z-zR1V#`3cjBG$H5FtZt|js%%ra%0~rhcXZPLQP6snc^iXiu#orVYoXbYU3J>jtX>! zdqjc#D*+a(cZJ0zNa}|IBWXVmVRd)@&FycS+{P}N8{q*w zhTXJccpOdiBxUv?qDYYJdP`DSK%^s@iYB9V`T}Becw5e;FxHZcFF@^xC$$t!5_8zr zuvv+`4=t(BBbL-U)Ol=A)>JpIA=Yvu6$>@glzJQWH(?|bk}WsL%}DiXy-3p4?m$z%#8%}i>{7nQ zUgaB@%D3oNzC%v=9{tJ>7*>A7CFLiKD?h_ge!*4cSG=YChIf?TaZULH?wWg@8Y?ul$-Dzg>Nyma@Il`G9TA*5Qiuk za(0+z5kh>IvX!BbKS9!V==ad6qP6;KJEfv6T5}f~joWHZvb)gPUzGNkiYMs=WAq>` zjr5i>-&nN+sJF1?V;C~`Y(?(BAmdMwOu-Ry6{Hp+GWDSmI^p(VFfP9d`%pNU`WvI5 B)E@u< literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntityPassengers.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntityPassengers.class new file mode 100644 index 0000000000000000000000000000000000000000..7650a42ad3a4a21533369b8cf9ad4f5736b94068 GIT binary patch literal 2290 zcmcIm%~KRt5dXdX8fF-kpb$_|f<|}2Fsu+2*YLGKGP2?aTUc6F$lKY+I;EktP4l_!JH>uxpj?) zq3|jqp!cTjc_PSH)fS0g79783h3gl_zqaoALA5N(uCz)U>+3{#nb)NVEVov#TFP$T z_cld9Tj5G}B|Elqxl)O@PL&-4Ml$8SM65O~`t1}EYb>uZt20ipQ0!J*1 zfOyG+ijWb%Z%J}z{R*!~m!#pM268f&ZZ+%KoGOsm{Sk(l)@@P3mLmM~t}3r1dtdeN z8sFq5_TvEQ@0OH?OC~W-l1y z$seF8vW>Q*eNRF9#?6OG_UNydL*J2+c;xu7GN}KIcKsK0=`S&$|B7*{pm?;_UseAH@%pZxSvD z*CKNcGv+*Uv=+>4RKqH@G()(TDMPnZ`ddv2S1=h>Q$hw)Q8gt@lV#EgP@ZvwQ5&<2 b{iLvgISLw>$5=#X5Mh?u*1y3lZdl3R=sHyi literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorItemList.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorItemList.class new file mode 100644 index 0000000000000000000000000000000000000000..c3e1e2c24f1b26717dde65e67f8b20aec49f9b5c GIT binary patch literal 1316 zcmcIkK~EDw6#iy++ijOpM66N)MXXxdhNT3Fg5hA5q)82@q@+ub@l#d!1J z-|*tat0o$a2Y!Hm#J}JPeY>EEp%-5PegwD2|`C?RdPKj_&ZU&Z(Kg(N6wmYe0(=FUoP zq)b?-?}Qp*k|VCcJ3~Bc$$I6~?x}weSIA8OGvinr5Bl#0$2SSply?>-wwzu!r z>%3F(`vZUIwKuBO#nT;NV3bzcYbnJ$RDDFluyk6MWZ(~_BN{>yW0fJPxa0kmGQ<5-PS45Vq5K=09fVOUAjf1tAz825KGqE?A&KjBc%DP$1nzM7Cp}&f=w?DoW-%-3y zydYkK%yG=>Y2;`v=#xKKfLNIT literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorLevelPlayer.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorLevelPlayer.class new file mode 100644 index 0000000000000000000000000000000000000000..a902f2e366678a80396c516bddcdd6e5777148b3 GIT binary patch literal 1770 zcmcIlT~8B16g|_gZA*cQT0uYsQCdKjA_}C2AQh8_6$msn_=3~zP?m0Y%kH+?A7O%t zFa8VlL5&ao0DqM6?v@A|d}ua4?A|@IbI(0<=iZqgKfiqkuz;mFB#gxo#aI;Maoom4 z40muhj!C2?WF$;Um}ZDP(hSX6VF;!(C5BMmtO$mFMKi=^vtAZfk(YHE8Bk1>>m_b! zE0>hL!w|9!piI1wgt`HQ&h7q+qI?TWBHY7 z=@n7Y9J$=A)yVJ)Z#cq|wR%IBUCO*^w1h=N_I`FhyRg4AKk=_fIR;7VC}4P*Rt(|D zby|aJ@dHP;g+)YitHY9&H`j_qUd@~JhS@YKxk4e+odab{tv48EyLF4%X46td$xRI_ zFvJ{gRfXf>-d%^QwP(EHC0D{dhV``Hd}VX)t_EJuF|7ILVu)fcyTje7vO$NUi_@nw5 zdjG9L2gP=SHYAl+&KAAvSejAI6*4av3O zKrk8qjL>`ZeL|Sf$mmx@ra#cXpvTuo7O@lb#NHwmd*|^^b$m~Gi3L}Y@?s6*8liy8 zj3Ii0xb88rR1&0p{julo7k~T(Act>d3?nNefov4FWGo^V zBh33zd?4-*qqr?&3Cj}lGGr9Q@sT)I1p4C`R`H48T9Z(ea7V&A!?+WfJp+YEDMQ+L&tpxFEeS9NszK)2O{>|QpvcQ31YJc6>JALbcGT%)P4`_fKG zi4+Xea90?Dsq_v*sA$!7hAU+fyVYscbi2xHO~NF~md2Yq+%^Q9lptwd|ga$5t~aC6jC}Ho4>I#PEGtvs$XNe|zbX`q;9Yb-ix5YOS-sPZzKAwo8r} zt#(rtl8cr}juFb)^L@KDbB;oCS2BEiNLlKfKy9s6tGrRPT5YRi*7K!O`eFH{ItNZHn=PXx#Br@m#U6ovVR`ug?|dhFiw@;t<5u)E}^90b8ILW z!Bwi`YM(k*Fe+#Pqb{MWU=v#mng8A%!h~%FU*Jmx_fSz##a9w`6nu?c1rP8I!*~C0 z#WKWux!$flq)uWOG!3V^gevDX_=HBkx)@dm^fJq^GMEU4OI*`*$C=6I7N{0iQ)ipt zy#9P`^3DBwA)Ic1>OyM4<9OWYtG$=0S6z9v-$UxBi2kUkgxnzKBjkxPT6VWzA%xOP}QY*Y8jCjn)xyj|SbTi>dds=EvugBEE| zwwT(QKkFHO8F-+b5PY%0eBmDe-lE@o0t{~;K$`%KDLNrW5}iT9(SRdrlAsbnjP9|_ zGXye;;B$nYBAiJ?ybtMDA_Xu(=VfAq97jkV#*m!AB;gdF71wZ`AVzB6?uvba5W<8j z%qF5oh%JXQza#u7_``5DthBCK?Tp(9-W4OeEbO+82aKB1E#!puG){-CFO z0ujNqHP8IZ6A>1eWC~&yJk0t7`{o#WddWY%5>}?|MNf;0ApK5v9fGCQ@Wy zn&d~p{t*jMCQc#1T-W*~x<%l^6cpAAK}3k85D3>t{Rgj9hVdTeJvNo70W9E6x~ECa bFl|s%v{cO!jChoCvWUA8v0N?U{%Z0iVYsx@ literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorMobSpawnerMobs.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorMobSpawnerMobs.class new file mode 100644 index 0000000000000000000000000000000000000000..32a732e3b8149b58687d44bc4e9169c5cdcf6e01 GIT binary patch literal 2680 zcmcImZBrXn6n-vw*<@K-jL?dGu|=dIp)9FT3PFmb)J6i-647Fn-Xu#{NH%G9q2gzM zfM5I7Fa4^H(vHsf1N;&G51sMlxk*|oFfB~R$>i=iXU{$NIj?(v`}^l#0gPZ>M;AtQ zbYnDxt2)MTElkO{hKUf8IwtX+jv%Jgay^7;C3#;hGdfbZp_bV&ZsLOwZmHer5I)o} zry-+ZUZBgfOV+I8+1}24CAU?rmD(N{QhaNq9Rf?0r0ZH_?`86pvgvMK8-HLvtkg;ct6+O(ZfkRs z4_S~^k7(_3wPY%*sft7N6uGMn2d?zJ9H?gt_pn>Kx-I&@RL6glHQg+zgQ*|d zklWHg58h<;XAh}<4Ide}gCzr}@dm?q^iH5Fc0ohdz{gltM|@)7Q`}{W>y350;#ur8 zS#k}m;4=gF@Ht~?;0vr8xDTlzXP^LL4>nrTz#587MSZ&}S%H=RukZyrRcy?Xbc*I; zZi9^|&}v%#(`W)6`}pX~qub~%RigsaEqczznrh92K)cN6E!XW!j1048r=yv@fGv47 z+bJer)&Bb?=ipKNPc=saD}f!^I7p!X(9;h966iimk$o4m9&E7~_bD_IpBz}>&|Q}< z2mIn%cBjgsJavejw9?avs*$7XhpHTB5cysEE1ty<3Flcm4evRhh#r5qrd!K+U&boR z{7%Dv{Y54?yO2$1+1qoicF3Mp&f(_;Hl_;fo0cc+3&xL>g=f)D9;|GB+Lm#FcaLtc z7Wju6kX(IeQ{$A9Gvp@8sdp!0PtX>N_@2W569V5;(uT8Kbv~hAgkSH)Ir2tB8|QJ6 zoIo$$Zd&>i0ce!T*pCSOg5ceFMB7E^3BtS3A7L&YY40RyJi@3V^<8vK_3)l^F99Vz%EWs1b;whPcZV@*>g`3`8psT|MNQ~@yP3SLHs)&;;Vz}N0{LHaazBG zUOkFIJ%({T&dbzgERfFX39RZPb>O!MZievt@DA@@Cf9ykBIH3t`5S;=L2tUHs2DX= zU?k$yV-QFUlJem)=??h*f~jFh{DD5b6O8C^GY;c?D)j&(D)s^yRMr?s6~t2wh3BUQ qkieDtws-lqjrYh4eD)Gk7w>>?F$pGlbcVQd3=2VZLmWeXy60b0Z|Xw; literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorPlayer.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorPlayer.class new file mode 100644 index 0000000000000000000000000000000000000000..614da482999dc4935252c9c580bf97315f7f7e7e GIT binary patch literal 1974 zcmb_d+fEZv6kVq+oz76O7DbVZH!g)DLlqPRD}tCztYDxa(HA^S4`rmCsWYc&|H4=Q zz(@5#jSqf+|6$@K(Zmlh?$Z(h!wab|v(Mhyd+pmgb3Xn4@DacS<_)xBz(5=WF$@|Q zLMn#g7)A`FF{FVO&E-!(|Ou7^1U|>&PraI5oV+5LxgFg5g-sam7-#ydnHN z-zbqKne%L3TI0T>^j%{_ZaD!%$89dTX#C+=crGh9p(%h(SZ>7lo|rZL5;o+xK{-K2i;n42!8|N0pgTy9_-WXP9pui@{i}H*m*M zOz1v*KVy&i4v(W9$EZPzw&xNTY8tM_aSc<1vFH|rZ%I)mG9*{Gyed(^Uv#A-YdNtg zHB85G9Wxqc9CNru+&bvF;uN{Q0QN=#e=(|w!E3I zRfuApsY7swA2L|Yb=#j4MQ+y`NsRqUba5$fHiS(#fc@>gl9$z-lzCuLvPr&)Nr#vVK8K z|B8hE4c+>84C+6S(SKrA|5dMMq>*vA8p@3>oT*osMK^k=er4;WQy6`8jvzF6l8SAo zAvCIQZq%EsBIZWBA$ZXp*W z5FEI1gnt1X3gW;I;71{5o$ypSL=m#QJ2T#y`R3*Q`t9=<0ModpK}AY~hEx(~G@Qjb zxulcGs2D?5!#E}sOe!!GOfe+pY{w4f8KUV-nITqitAe4wXggwgt5FeNiC5|*87#UM zua~)JOTHtF1?#rYaO4ILxas&!VFj*tr_Ni#D~om8l8U& zVX|8jQLE8pPX$WaBK4xZ-yyXaGqf?-D?hWd0Feo6RQ99 z-fb~xD`5aPZCUW6yBBV9gKu*kI{Fy)+;v?FFYFKn7j){|i#jghGWFx46WBpZ!HkY8 z$SauBaTU~`_x@YoFbqg+Mx8q~<920(x|pHYwEWSg41Is`3q3|d%{Jamf72YUbAL&+ zZm*SEO{&sRy7(*TmB6!|THegur`k~G{g?`Bk6n&+Jt$_6!4^f0Tdg*3?RO@zxLh(z z_ZXIXE!Qur^cR`$4KL-8TbA(sRPOQ=jo9m+=k+&q-Th&9sj-XZdwlF8BJYWapr6)+6sk`#K(yXIfPFYX9K%5j(JGbSAWjc3ksXWZ{P{G=1BT z!#G55OuFc}m((!HB<2Ym!BGM%sS%>0I2PJwS%R%&w1aY%c6msK$aW8LsD0q4k2q!Q nWTMUA7%N zSY!w%CpQ@)dADpa3>mg#6`J*uum&H(+rv(DXF^SSYE!yecvLv>xSvpHNSc(^N#ke>($Cu*$%W)vs$Hzmw6+wJk72* zYML;Zcb#3!qa}YUy_KHZx^`ir`#xC)$!_n?@OIL0tU#-i|E9;c1I@QQGNbLbZKSnA zu2|%iyjyR$O{bjI^~vKYFepwb2zaGt`vJpLPud2_lACOYKAqrgTOc%APNW%9J(=lv zP3bc04F=hFo1STHS{~5>_bOJc~sOW`sMi@>xRcPiR?X@}Z}p!tMbHa8iS$*;?>R&3{_NG_5iuBYS zhfNmo?S0yd&NJ$?Fd3#MP4?2|IqqB3q`5QR$x7e4z!-w)+d`$dJ`NtL#+fZnp#~GYO1gGdd@dTbE3{o_o!&8JB@BA%y z{_c1F5>kgK3Tm7*1oXG?G+7C?s0pINc!ub4#O~pgglE}bn33?@pNQVW$p?7K<_S!; zb3soPx?xC9B$9PcZZcSkiFZ&2 H#?siod_IA7 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorTagged.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorTagged.class new file mode 100644 index 0000000000000000000000000000000000000000..6155185f728dc213e44269366db68e4627efc080 GIT binary patch literal 1481 zcmb_c|4!3T6#i~kDC;^v5K#dE#kn6y8BPU<#5iNJI4}W1qW|DscO7M2JK7F|Z{k~M zqF^-f0el`c(M03vHbrz1iKOZ6y{Gp(KfiO{e|z%|Kn6EeL~v0>441-C5m%7tLQ+Kv zlPY9f4wfmE{^$y(6{Ho+FoY^%hhef{3tz9AwlG}&*w;PbZVOl6POqmk>&t0<@yDNg zVkgVcId9sgzrZjMFKqH{u3OwL>npx%+U0CwjX};iCBe{BAly>DS`_XoFIpt&D>w$X z*0^g1=ax|RH%yPA{|@(g-u7z3@Ern_%c8`fQ_CWp-{$f8w}S zNt8@qFV-s+`tTC3`Q*1*tyy}YE$7%22Z_A(W+*cgZH!PvvcFSnxc5gm42s$GiQ!TF zkUTBjUM0VCPPOLL?NT(n1-K}_X8^WjrDOOh+;Jao}p`rG9n+g)6p$8cSS2bM2bq!H;GbI0=ISi6nQZTDw z4mSc_y&AHZ*Ki&~49mw~SccyHdfqQ?60sPLl|T&91B9Xi#)Ae}_`hHnBHS>9=S`$D z)6)#M+V$BX9QmzhC;wijgUlrY5qp{q%@AvAeLu6U#;3U;w(8uXE2p3Y% z=~CzyQ=c&?eZi>owP7mRRPxi*IEFDoCP*>PVYK1MIL2rfB1xc$jgncSHytEgXsi?D UG022O$%tVdcCRxJ5W|QtND2`VS zf1zKAD&~ zklZnLMg&5mrfqs-0{&R{l0YC;${PZ$8EVaL6|;u3sAny5qM1@ox0ZCrl;?eBz*{$6 zfsQHN)6=$FHgaCcIWUC+Ep6L|ld^QzHF#XkP_tOJ5)v>~vS~P3?n=$}fv)=R&$WT;Dzj~S6<0&~T(K*TL=IXPoV zmO{kSor2+2>E;Db&uz}=rjJ^tcD!&thjk2XO<1}46HGh8VXpKGLxCeZtZB;z$W{Nax5A#!nd|w!_%zAOxE9T+VRa zuH;}pD|>uIdWvkfknw0sw>VUfDAW=^ z(*2OLcU^Zm;^)>DcgpOejygDLsnHByC#_g_vre=rz+ziY5e@5a(6!%gb0abl@3 zhE+XW;@^a`5a{F=a)NR7!zU*lIdAeb%9E6}#Gk?!kNTe>@DqYRkmJK!TvhIf{DDB^ zPoe=@O&f2cizk71aixYNt|EvqdAso+5&Q+A2R%`xg78yBDo`K8?ujvAPU4LNqP<2? zr<0F$EboTIch7(8`JQ(8tM(7jVnqJN<;XvXNA@rjd5#HHU{>{ESq)%S4Z>7Ia8w1~ zkpHc!RsEc&FU$1qJ;b133S;O-od2&T_~}6}eU0Nj-lsGmecq3Ur25E{5#2?CI*cBv zeo}rUNw>nchbaXE3O*2j;bt3{jH|T};s$qlA;@Hi7dZ$?Jm%mMMIAMT!}o$1!nNwP f>y-Kk@ecQMeC-T#dztwgZresFYU$;&Q5GFEREHQmDkd}q|rRBW0|M^DcrCdk@Jbt*cMjwO=uWQy)r56$sp zY%(2BXvxt;G$uftI+Kh~B{Ts6Ejc|CP0mac)$5YWB9;U+Gv}v`1*2rx8H%EtyIpV= zbvvhI$+HFX8hNFRX=->KD>)^GXGhhU80l8eZ*8aFGOmuZ`t!8i3$x@Ups%aaE zN@3n8CG~lWC?YpGwICqfr7r4Ax?-^mXl}{0bHmlFY*jHss*};JS-oU3+cgKgwq77V zLXR4!>W-MU=^hhsd;{O&o32>*EUWxwlM)-y%$%*el@gik?Rp{&QqFM4#%HQc-_!LZ z4bx)jh54)=F1xyGX2Jskc9Q%f*%sg*$yl|JJzdQ0xjL?xT`7!gVZR-tR+coUQpy

VYD80>Sd>1L<9s+I*wa*OL}qAa4$RA za*Gci1`#Ll5i>#x`VbNEv5bCZyPt`F!cGc14KPIm>@>(ugG}YNwaT%Yi1<{%ewK|* ztPk2`8OyOL+v{6kYJSnkxKxp2|1Yfq4%N>JU(3UFP4r-}*T+DHTkGX&Y;o3ulAg&J z<#KpnfEsuEYU5U1(^4k&B1!t$R!#6RZsuxN?*w>?6?!+0)T^#VTIW-ZQa=$7(h;!@ zS1Hie%9Qj4S1B7MdM}iv>SHm;-;iz z*^~IALr+eWUZ%Ex?En#9%J>T3$~cXXxOM zt}!g)djWeNNytX=2-y92z7vB~$bIycBb{ht`v4$F+knH~8l+k0IE^`nG~^u8h;v8- zP8vdN4*|hlZ0iy3LjXr`6aro%tdk)7Nh=U;q2WF}KN2QjnErkIE=Bw!c)7+uga%HP zLf*(7G~S1o@i(mFKSmU}%7x=N!S89Y5f`&~0UnAC=!o=m+=egG_Y1^3@b}$CKtSX! zBoEI1#ATQdAo0OPSt!?2(l;}BR@lY z*xfu=S9Q0ssxBz8=B^31b5Xz(YI-;`bMWI8OjH>K9~#L9@Yk>Krb4o316`l!u0zKS`lk2RYM^40_#2QwH^E)J>eJ|= dK0b&FhI|2hjqmUc+F;Nas1yV?}2RQ5wFtV>^W>tD;FCV2@ zsc8?>JoSU;bn=iXbxy~h`l0@Z{t!=ApF0Z!qR27maCYvUd%ySl`g|XE`2Fvne+94> zXB9jb#3DQ&!eYE2XD@~z&=p1u-C^v8rl2Q;5+oI*LeSA0B2Axyeo1D?ojqaPj{*6b zR*(r}9rj;J5n?t7?_NMu*rMSij+=*uI>ZPU$Jbj`b7< z1~_ObEpO{)%*f=^&hh44cCT)7$?C4_u3Ou^eYND(U}O!uQ6LqaF0&~$uihcxZO)~1 zf!PTotG5+0J-XSc^`yBnFOf@X=^dJB$oG*&ue4NP&Q4Ry=k=891Oc@ro7K(cv}Rd4 zDYi{h`KpN$q-zR!0-!5+U7)0MFt2addv#OKCaLW}(Ob8{sUuN!6K#Alw+v>rjFF7D zv{X+)AuubM$qTGZWOX~1q2rRK)@#Qs-6Wo|y+ttVVr`Fic4~dixlBG+$fjsOX-c;Y zQ%~(6H-)Z7#n#j3{m-l&bEmdP8StypiWiI&3XD(5mH~V=MzSqr>RSYIeb- z=0_Sj>l1sly;>|S6STc&kDj#SjWZPuMJ=WbiBV;hWHF@$E>1UltHycp?&3^pdzXP3 zmW9oY%HW6m&xkOWABBZn%VZHN#!bOC z(y@eL*>c}ihWooG>^ID;=`y(g7ZGCyH^$it6}&+&GwnN){dz`YrHM{j;Vg&5iWNzz zpfKo^4yS@_F=SV$xCuYEajldoD9|W-<$rH~DjqKEzRJ%`p`#QK#Y~9A^)3 zij^C5Dn7<1Dn7*t;-uoFd^sicn$ciW@fl7_rO&ANTxu~B+}$`+@ddtA@eFvKXrCrN z6Wc!1bYgX9*PF!eqgOHoUkN-o3DLxU%A3v@BrUv+X-+Mg6_vN6kd{p97Vmbec)Ob$ ztsYkr*piqa0olFVvY!RWTri8^f4$o7$sIq7o#TBNfTn!@y-FisTjQNd5hNM;Ylp>rJ3JqUjCM0Id>oAY%3{dahzSV;xarnS1_xl_Aag4wM#Kf=4B zwzAASj5$91KnY$)&!vvEgP4y)H2pBwj$k$GcN31{aU4TCjyt+%&l_rmj6*ScgYwja*xg4UV;4s3)CtRTtu%c`0ct8qi2Po4BgF^czY47*_%if1zEW z^k%+!u!%o5oucE#1#$>-eTW8mu3|2IirS_Fv!367C(7Ku*6QE}1wI z9ClKI!^@GdNOE-~RMZC|fug_f^GbGq){Z%S9Y5QF6O6Hw41rVF$S&1F1$R*IZuXQO zoP~|A89L{1o`2ut8(hM-4iLQvk+vL9(3t_AT#P626oEKTS8heC1Lu$n$q*rFbX+{- zKqmum$c1Fc0ntl6&Y_J^`zW;uPjlvXz>xu4+}q~vZRehZsRF(ms8P_NpmXhYcy6G& z_;Q`;B4kf2B1T3Y{sCbbf)&H4^f=*HOcTGO+r@F|5q5PCV<&ACJp3$=d$0?&9BZh_ gBCf9BN(`@Il|Lv$29Iux@ZTG}C-J?4W5OT&7oi^JegFUf literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2.class new file mode 100644 index 0000000000000000000000000000000000000000..7cec17f6118bece2a6f9b209df6390a49002d4bf GIT binary patch literal 26701 zcmdUY33yaR*7m8Y?sVm*fzSbDRa9h2zyP8s2uebLNPtKJ2rg|W=_C!E?%3U7a~bzt z$8Fqq8TWAzl||h5-ErUd(NV|IaT}L$`QNI#eedlM7C-xY{{J7Jsnh4ZRi~;>ojSMb zRNe5zFL&NUMB{wDEp`E)rIOhynWK{0LL~dEWUfl;R8p^!c^03~7Xg^u3h=1Kn|X^xeR->T7PBB{v3j;dC2^Is zNuIE%h$mIj9^i*rv@=f?@ifn+M-|Zs{)ZwO&5sTd0}S?9l^my% z;{*HzMNgFcqyRrz@>3)~RaJ4CjLIZvn;2&9Zi30y&(PjK?)x?hj{1c0=RI)y` z=xRm(Y0)Z0KeOmsMgL{d^@@IO(T$3JVbRTs{@bEk6#deo)rx*)(Hcd+w&-?6zp-eo zqTgDyUeW(pbf==a*x2Mg11NqG*9duPGX^=nX}sMQ9nm6TZYk>~~E7iwyXKI+$YD(P#9e*8EjqQ6Q8 z1jIm#zCr)QAhCTw>|oJ%O44A9J`}xFB|A#7lN38kF+_@8q!=p2Fe!#hF+z$`Daxc6 zDa9x$c9o)BiqTSxkz%YAyGb!liruByLyGZI>?y@wQcRFyq7-{eF-eNaQtTtezEVt) zqC$#FDW*zMCB-x;rb{tHifSqLlVYY6HB!uyVzv}>q^Ol*e<|ilQ71*c6!WB*FU0~W z4v=D@6pN%dP>O@3I9Q59qzFrKs1y+?8l-5HqDhLV6wOk!NYN@qOp3))ERiBEMVk}} zDUwpOOL3SKDJjxYWTfbjVyP6%q*yM+3Mp1fakvymNO7bTM@jJqDUO!n7%7gG;y5Xe zm*NB|PL$##DNdH+6e&)X;xs8vm*Na5&XnShQk*5l*;1S%#ko?PC&iznIA4kjq_|Lu zi=?<%ic6%pREo=_xLk@Wq_|RwtE9MEifg1;CB>hmxK@hmq_|#+8>F~VikqakS&F|% zaf=jxm14CNw@R@_irb{PU5Y!TSS!UkDb`D|L5e%2*eJza0daRg+!GM@2E=`gg4Kyc zG*uaoq|?zfqkdB(nMida-5zbsBvX~iwzf#3sUn_iT*7ET&a+v`hPw91G8D!yl-yx+ zPh*K_V#RYB$hx{ zZY6b@R7Yc`BNb)TH%DAebZIo6t*L*`BZJP5w#FLcDA!v(tV|}BMpKz+sxH=&sE;m3 zZ+hk6715^ZOth_YcEGmsLOI#%lR9(H9Iz&mXkj!k2diuCh%bqzDw4~+gWxvDd2DLW zZIoTu?z>Z{HkpYf6AL2fj;(v=kXfL9G&Ly`$wg;GBk{~8?U*;OdTQrZ zyHlvMLS{LWrjz-p8CTVUw&&tzNUNJVx1}PYW_Ra$r=;4Fsk#hicIPLvlu^VYaV1IX z(QySH>(0SyV(Cmk+;3OxJgSehv_!MbanP(0<<3QI+1W>W{yG}2I;#*`= z$yB^4+7!!_H*_pn0%GSXkF~YO%j?=>Ey+xH>6q}CapAdRCo&4msjUmouBc};swNT5 zl((s|N=2G8<>_b&UZUL2JEnZ);Omc zB;XAR&o(iS1FIC@b570FaP?HxhM83h!?UK;GMcmXMr?UHX{V?r+RW$*J-iZK*YABs z6NYDaYESJ=u|Hf+w0dVoMJh`6`o5aN|8{Fq3C@v^7Li^^peU*h4kR#z=gA z1TGQ04f-;zF_=@gWGaT2LL_dtVBnVP5Sa+P_O4s;81NHlZ?@@Bq#kwn(Sp5WiCAVb zqe;W7Jr(^n-!)=BqatN8^Rev05&+^GI%08%uNdwb9Jq(Zj#LU>x4de3w6OyVL0f}c zwmKQLb7L{M6>;#Qwi9A>gLmk*+@YK~?zprZud-zm>ZIQhzjZi#8NI5Rxy?hc^%gS{ zjcx6WZv4NehU(v}hr)ESBh?s%9WlD;|6;@c2QAM;QZ3O8S{@J&VHT^E!Q5zb6z1ND z8Gn-LOc#b;S2H9h@5J9`JHJ`Q#%FCyL$HpBp(j|-H7qABP7%IMO(TJW~6EH~pC6zsHZqH@`V&MJn{?BDBoa>e6Koz(}Hp;)}? z)$#vx`f%E&^}!ZHC-&<@IiS4g#H|AFCMd$ZAANDy3N{v=*O^+Z;>Fx2cWD4GV$Zun zJLS#$!WI#0tW2`Q=9mhWBx1NS7w3`FB|Per&2RQuYB#4k!f3et=JzfJ4>VoyLR#>q zFxE~>qAMW3q>D1xU~gJ$9afuaX*H~idN-A?suidKD~e4;sSbEHh`qazsLB_>-DAaw zty5PSw&KNe)|`w+{+8?r&tg$&8)|k<$LOrQdYj+0-q}>a)zwNxMRp_2CckRb3M^4u9ChIsx za_`2ty`K?nk#^{-POm4YA<$^YnVs=;mifD?HU{}fJ}Ss}<>f&>MkT}fh#-59y&Yt4 zspLiWQjmS9em&1#2#805;!*J!=Ixf%n`_WP@i_Y>$o|WI3W_JhlNf6EmEL)48D!sx zr!d5>{;CokZ5U%l)o!WZxvNo?JRM}OvsZ%b4fbY`58?xZd;lMaP4(}rq;te9Af5?| zXT{%CmCps)2kh@b@w|8e+TaB$u~broAy(@METYwGGALdYF9pTR;uQq#ReQQvw3E6DLxB|e~C|m;&br@qkJru979xf{ToAV-k>`2 zJvEuoFQ;PND$n~;S+oug8;|N&Bpu}2^BwR;@CcaIq2tE}$p(EZTchgD+$$HIkwj<{ ztDWu!&K{p&DO8PxTLPPOyyA+@LpQ)1~MpXhOr=}t;DyU$$P-8ega(ZllSO&EQO%+v3 z5w=H-c9W*JMpVabnbUC~kjaMoZJF*tL5Y!&1*#Cjbp_eS5_TTV)j3BG-T};tx5uP9 zl}t=e#??8Fjm(O)v_&dA8qj9D+^mjtYbu#+)9SGMF{d#aPom|vrfOpd_1FUNJ6nmJ zd2XbkA?A)lT`N@SDAqZ$vB#w@7RO?=Ss!fJI&gbp_b&?|lox>w*mjde7sN8H9@W&v zV{Pb+J;rs3Z>j5j;avI?>LXxJGYX}neK#v91Baa)+5E$y8JJ4AL^J z$^|dUcL?$z@5ZP;-%U_n6Wal|85K||*5vkaP!IP(rEx|C~EMc~wI8PElS>%iYK2*|f~9sJyn-dj%`6nl*cYp!ieKR&6yLG4OHTo`YUMGcp z=QpqZ#=T#hS95S~Gh0qT1tFJ0yp#1UXKbkdfe<@ltnV-?-EwH%dw|AhCpS=99gpK` zW_(JjrK2sH$W$$FjJB(L$+(j0W-_tHfX&8nh#5F}OLI8XOcq zh#!OEzv3sgZ5tL8KMNJT=R7EW^-<8rd>ki6fPF$CJ{(rMLF6eZ#LQGoB;fNS@XcOA zXv2LvBa&{_v3y@l#bta2z5q%ahf%d0L64ZaH8LmFfXLDE_Ha`D=xrWPNkt=7&CR$* zUl~t!Ac)p80wf&OP`J@x-J_~s;TGrmbB|>@S{F_`4&SdrH>_}m4B!*k_>ZY@7cYfMo%=(zRDU0r_sIEU^Xg0zK9XCYcag<9t zKkaVUsOvK-_GV{jc7A4~k!>jHX6T+)eAvxq2mN#~xHcL|p_Zbk3Ll5t4QDq{XV6zs zk)tHKA{tIMhfT(`x}XZQpk3c&cXVElz$~suFK@3%W-=2*b@L>}S_u zf|PYjI#geSj_x&U#|rCb*Vm>HGQ|jrjJk&$GUGc9y@G0O-_xzxu;B*tsYJ2ruZ~oP zQ}}iwigLbI9pKDrNqu0EQs%D*pu7Iy0({sWiEK9eem`2IWOPp(KHOjfcDU3;-d&~l zXwsp0kJfvv)R*$ZOYN^Nlq}oE!mZ|Q9kjF9Y*9qr5)Z4Z$>@7QlYP|TYtu&-*+J3) z{AqBO@DDwrOL1LN&EasfL3+A~Q?FR6!pJ2{?EtdM?L6Dg=oYR)eHjAMq0X1o%r8bB z&A6HSo6Ol=U1d(#tT$dY>eCfH9^p189A!s^E0XFY#MhunpIkv$$w$rgPwAHH-l(FX z9zpgr&(`h+Jey7E)05TKRW>Uu3dROo@?`1Js$-}gq;GDc+|U|ykv8Amcyb3Cvj;LV zJFFP9w0)rCZ&61n0L%zuzNgJ8fWO6@xOB6J9(UdKX@J!8O#duu#K}-NE6GZG&LjK{ z<_O7ZQ->tsMtw>WG*i?VAgVNz3X`WnY1|K19TF6p3NR(%V_f$au2L2X>%~)Tc(c{3fq!Nb0~vM%46x47bNXdneJJm54V`J9lvej1u6R|CVN(s zj7L%x@Ir8>?do^9K{HuTiz^2aGz!+Ks9mT=aX2?Y?=1a9DGN;YWI;`6rTcdKhs?Id zaV1sC`&Fh^V5-3lbu$WV%<=)-pir^4LA(XsrLZY#0`;~RwKD}4cPxoEBr(+ro7}K{ zpeY-y@9qjwP8O3vdDR@@UYjdwOE#cm`g@Nr zQCE&Z)IU6D8@9{$r;Y31&J|q~YiZ3)jb`-sZ+L4rMOMTW6mD{`0y9~2bOrB&0XFAh z_`bqrJjW-~;>l&v6c+KYlxF=K%?9Ibv;DnJL4*CnQ`{5L?14pr`K~Sd!pXIX>G+Ii znOZd{n+UgLInSYu?JZ$$wxi4nDso;i%67WBiou#t&0>{KMwxB;cqV7J?OfzwG*k)b z;+6n5=lZ)HXTi5~S2gL|6z=y9xY*TIuC6}j>AF4Y#!x;Y7S0VIT;bOrKjq{4fg?2F zlejgv8O3$JoQ!*YTV9r%8!zTCaQwEa4_?muEtE3jRI+V0UinMm115Q|A?bTE&;za( zZM7j4k#tmj>QFgj-t3upA7qjqk=s^!lMg&p)$nP<_4T%1-iv?wQ&)YDbhj{L3DY?5+AYIW4~!rGq@OwZLwlB+!&eGOvK&Ct>jRP6MQS6KFou+&tBv6 zHs10T`Ybp!ujaD-^4yEGA$*JP!{sSIcCT@m(hgaP`fg!!N1{jt3Q=#@N#=nX*R#WF%&D-tN81VY8`Zr&D&>j(IVX%kpoL=9Hd%&D9iu9{t6 zUB8eKZlZ3hZ_1gi&Z}m~7;Rn!S%KZE>#Jsk-LEPAHC6MgYG7TpHB%N=&Ba2du72*k z%KCY8tI)MMwe|Q+vks5dXQgTzG|H=Odxm&>XdwIbh4F(gGf-#qvCHBO4MkNtH)ONl zVd>Fvi#gK ztrpSmmu(PjzlX}UEYS63P&|~4>BwkLZ|`k0@4~`2h42>_Hskv0Y68A)L0@-Y&mi9u z_aOQ1e2<&}S}dV9-{m#>9yIPwMw%n)Z#G~i7PYxtz*hqMt-)9D9k^xol((I>0CVk9 z#rERS^bnKN>!xip^t3&vpn7$9vv2!DQ{|S+dMB4Hxe}q4I_w-L27J93?c(~8oSJj{ z!)W_0=cB>w0(K!Wb`kz$OGsTF#veB7udWko`Z9Y3&tAoE&R(NJbrl!C3)O90(2%-& zjOXv@=kJ2Yg=B|+A7yZl7SH;to5>FT5qN}A9sXn50lzyFAL!uH+o`Z@ zEm`+b(X2HT9J!vl%~sf`wbcDS>akka`We#hgwMxm8U<-O^`aTy~gZlsp$U_at{p}Oa7i=2c!N@QW_S{hiko(6Rmwb~=9kp0YlL1twJze0Ul6iS=H zn}NP4^;uff!1c6!XIZy<`fNF}EL#>za)#b>)j+O#u1um1gQ85L$VeTuo_6RgcD)vB zM!m=pTjYo>vc*CO7pOq!3ZN-n!D74FgUUjKiyPO{ju%l7KiASu*O8A;DlN*MvlC6(z1PvC($Hj`?xWLvbvi|-6*{fd=~SIo>2#V- zr|WcvPOEjgpH64$v__|6bvjyLv$L}>7hEEpwoy>8+6*J(-{*0GM3ng`1khL(FqW`*~`%FR7E zd~*+u*xZ97H}~ME%{}--mk*9!$kx#@rjfyobgW{JGwksj=>)}|=&&a#_GE`WMX{$k z>}iTU-LPkDq%$#`e{{IBz@2Tlb2iesD(iWM{nJJ|U$GZB?1hTG$gmf0q)QZgDOks2 zv1znFCfC2Pn)nP$M$9Y z*)%qQ)gZ@QHi#X-wr7X19as|^%;IcEmO-f_*v{;DHiVtdc46nSq3lvNjIDyCn^`G) zn3b`&*+?u*M)6{{D<8qic?BEI4`gF_hK=RNvEBGNY#hIe?ao)TJ@~zBJb#Am$=_sq z@lV+V{sWsRB->kT$0muPY_fKI%4xv`+3t?3&%KO$;z#0rhG*B|G7RD6>*xw& z=U0Ne%5WI$tHE94aI3)m+2O7Qcb(xN<$7>87!K3uMsPPd&u#|y7l*qA++Q7THMmb8t%T0bU(NUoM#V$d&uD) z2KR`=JqqqIhkG2{6NW?oo&@)l^XzGG&lnDEc^2H?9PT-A&pSC^0QaKv>?Lq78xAsG z0r#rm(9YMuz3$|E1KgX2!)$&F+}qBxcfh?1&Y4DZD(!^fokHDN1r21CRLZ8(o~(+d zVS?4O>D0hxP&=!pqu73QI-5xsvl_ad&B7F!O%Jg-^gOG@l-Qp>XLIQ%R);B24?~{^ zqn!_vU%)D0;I(WaOnec{`#`pm9mGy%2eb2mtYTrdh8@c8Lx}Sk*5H~Vd)79^W7QXI z#uTv@Ex7QHR!jIS z&aS5h9Z{?PUZrLB8~;7^#(y8x?9sW7HY#BWU5D9E^m6LxW!GV;FH&vEM_{%p$-Azh z4@x)C-__dc!3Y5R@z(ZY@N4-Egup-1nRY~8m1Dx_VuA!e4J}nn}7th zU+G<1R&43rM7K3`2G;o4xiF<$&vKi6P8Rz@?@HZ$Yi~XpTPyXy-nvRB6u?DF4T4JVOsI;2|jySyOzGZng*-&D_W(&@g+oT7m`rSiYO?{bZ*TlbudXb~-WH z(}^JQpQ%rPk7Ga3&|*u4eC*zgg(0cV%Z>C6tmfO!+rD>n8}y5VBp>n;+So$^ufi_@>C-kRo##XPbjJ@IgbAtq0QT7DG*&V~^j|>>N<%+s7Kni*++tcQ4k%V8vdnr@;_c%Qm@$l^Cp- zi-nQ~>g_@$tdGIAbFomuKz&`Pg!MC6e=jz`U<19_AcJl1Vxd+8?cjl$4K&z=O4yDD z+sTXVY_K6-Y!`zKb+J&3frfdYSq2*Jfo2kGUl)-j& zvCwn_m3yE=4K&&VMGQ2?g-V!R=WbqXoXNMl7u&;NwbMrGY9u5SAgz%qu<6AqJZ2fvOFJkVLj=p{RkTd7y&~ zgkXh}YleYlc%XU%A&lYVsxr`i9>{L}Ob>K`$yMWl_AwB`9geJ810nX|KvNBbK!^i1 z8mQI-O*RlhBu=gd10i1GK+_C_#i0Z3XP|lyw7@{~JW!p15Myx)&Nt8k4^&|wL|>d- zQw#+6=|EuvE%HE3211a=$+f?M4)Q<;8wlYWC)Zp99pZuJ7%1$4Y7B%Zk5h1-fg&zc z!fb^#dNI3Y2>xV?mN46qAPD4Qw!c9@D2s(Am?{>#PzhUNu(*qbjx-QLLr%$+21>Y4 z3A5d3yNiX=Cfi{i=x_t2JkSvaO1n@A%NVS~i!C+SGB38=U@N?s-MGVDEM#Xp!i7qh z-L0d%*dL6zqrKQM20PY^9cQrPz1Rr`JJH2LM;YiO7b;;V8|)M>cB;Wn^J1qP>SvDhjf$668TIh>uq{>V;b*RYe=I&6=hV5i`O?^K+ZoyPs_bl#7h!AG()u{!!A zpUckTQFb<8&d%Ydv2*zq>^#1P{fR%!&gZY}v5KyGFdsR*6s8pT$q?T3-)#oo^?0y>EARgKq}A(RU!b z$(LX^`;K9M@twzR@mbsMz_C3vR^}Wm1_`YVh`3u6naa(0*hR(7}lA$E`d6?U)xQ+A*K7j}O^h&@m+ls#B5fjv|(i#=Qr zVUHAK*rNp}vBwH7VUHKw!k#F&pFLUdB73UfWA=2xPwbgMF?%*Jg#9fro;??s$(|2{ z@h6wk?8U%I?4`gZ?B&2M?3KU+?A5@_?6ttB?DfDe>NEZP&%%u`0)rzy<75#2JnTy$tje(91zj1HA(D ze9$XFPXfIP^jOfVK`#Nl2J~FeRiGDw{u%U2&}%{80lg0NEzs*h-vGS<^fk~ML0-=%b)(KpzIZ4fH|K+d=OKy#w?fP@ME4 z+Ia!ivG|urK-Yt=1>FF8JLsLDYd|-Gt_Hme^cK*&L2m}V2lPhJdqJ-Uy$|$S(ECAG zfj$8GEa-!v>p>p^y&Cjk&=lw+pvyoX#a8z*(8uwQl$-_n1n@IKp9H-O^eNEMpidVR zB3yI_(Hy7>c^L2*bq74%P^+P`3k<${&fsr G`F{YO%(j=nPV%gM?y~5EU`>9!f-I)e*(AuDa;h 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 B+SLF6 literal 0 HcmV?d00001 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R2.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R2.class new file mode 100644 index 0000000000000000000000000000000000000000..82aaaebc0b8a880db8f68442d78068c4862c496c GIT binary patch literal 26948 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 Date: Tue, 14 May 2019 19:52:09 +1000 Subject: [PATCH 135/366] 7.0.0 Release Candidate 1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 839562495..3b8e3bd23 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ println """ allprojects { group = 'com.sk89q.worldedit' - version = '7.0.0-SNAPSHOT' + version = '7.0.0-rc-1' } if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost" From 405bf8dc07b30bfa6988019190e1f61666df8caa Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Tue, 14 May 2019 20:21:55 +1000 Subject: [PATCH 136/366] Back to SNAPSHOT for continued development --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3b8e3bd23..839562495 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ println """ allprojects { group = 'com.sk89q.worldedit' - version = '7.0.0-rc-1' + version = '7.0.0-SNAPSHOT' } if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost" From 41cfcb6d55f41be11607c57f30201b48b2b96c3c Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 14 May 2019 18:34:53 -0400 Subject: [PATCH 137/366] Use a jar for bukkit impl adapters. 120 class files is a bit much. --- worldedit-bukkit/build.gradle | 11 +++++------ .../impl/DataConverters_1_13_R2_2$1.class | Bin 300 -> 0 bytes ...ataConverters_1_13_R2_2$DataConverter.class | Bin 446 -> 0 bytes ...ers_1_13_R2_2$DataConverterArmorStand.class | Bin 1362 -> 0 bytes ...verters_1_13_R2_2$DataConverterBanner.class | Bin 2179 -> 0 bytes ...rters_1_13_R2_2$DataConverterBedBlock.class | Bin 3023 -> 0 bytes ...erters_1_13_R2_2$DataConverterBedItem.class | Bin 1474 -> 0 bytes ...onverters_1_13_R2_2$DataConverterBook.class | Bin 3342 -> 0 bytes ...ers_1_13_R2_2$DataConverterCookedFish.class | Bin 1586 -> 0 bytes ...rs_1_13_R2_2$DataConverterDropChances.class | Bin 1603 -> 0 bytes ...verters_1_13_R2_2$DataConverterEntity.class | Bin 5995 -> 0 bytes ...ters_1_13_R2_2$DataConverterEquipment.class | Bin 2350 -> 0 bytes ...rters_1_13_R2_2$DataConverterGuardian.class | Bin 1432 -> 0 bytes ...erters_1_13_R2_2$DataConverterHanging.class | Bin 2219 -> 0 bytes ...verters_1_13_R2_2$DataConverterHealth.class | Bin 2448 -> 0 bytes ...nverters_1_13_R2_2$DataConverterHorse.class | Bin 1612 -> 0 bytes ...onverters_1_13_R2_2$DataConverterLang.class | Bin 1403 -> 0 bytes ...ers_1_13_R2_2$DataConverterMaterialId.class | Bin 13795 -> 0 bytes ...rters_1_13_R2_2$DataConverterMinecart.class | Bin 2039 -> 0 bytes ...ers_1_13_R2_2$DataConverterMobSpawner.class | Bin 2400 -> 0 bytes ...rters_1_13_R2_2$DataConverterPotionId.class | Bin 4550 -> 0 bytes ...rs_1_13_R2_2$DataConverterPotionWater.class | Bin 1826 -> 0 bytes ...verters_1_13_R2_2$DataConverterRiding.class | Bin 1936 -> 0 bytes ...verters_1_13_R2_2$DataConverterSaddle.class | Bin 1777 -> 0 bytes ...erters_1_13_R2_2$DataConverterShulker.class | Bin 1347 -> 0 bytes ..._13_R2_2$DataConverterShulkerBoxBlock.class | Bin 1306 -> 0 bytes ...1_13_R2_2$DataConverterShulkerBoxItem.class | Bin 2726 -> 0 bytes ...ers_1_13_R2_2$DataConverterSignText$1.class | Bin 2819 -> 0 bytes ...rters_1_13_R2_2$DataConverterSignText.class | Bin 3133 -> 0 bytes ...rters_1_13_R2_2$DataConverterSkeleton.class | Bin 1549 -> 0 bytes ...rters_1_13_R2_2$DataConverterSpawnEgg.class | Bin 3822 -> 0 bytes ...ers_1_13_R2_2$DataConverterTileEntity.class | Bin 2989 -> 0 bytes ...nverters_1_13_R2_2$DataConverterTotem.class | Bin 1318 -> 0 bytes ...onverters_1_13_R2_2$DataConverterUUID.class | Bin 1324 -> 0 bytes ...Converters_1_13_R2_2$DataConverterVBO.class | Bin 1102 -> 0 bytes ...verters_1_13_R2_2$DataConverterZombie.class | Bin 1955 -> 0 bytes ...ers_1_13_R2_2$DataConverterZombieType.class | Bin 1618 -> 0 bytes ...ataConverters_1_13_R2_2$DataInspector.class | Bin 417 -> 0 bytes ...rs_1_13_R2_2$DataInspectorBlockEntity.class | Bin 6401 -> 0 bytes ...verters_1_13_R2_2$DataInspectorChunks.class | Bin 2596 -> 0 bytes ...s_1_13_R2_2$DataInspectorCommandBlock.class | Bin 2308 -> 0 bytes ...verters_1_13_R2_2$DataInspectorEntity.class | Bin 2676 -> 0 bytes ...13_R2_2$DataInspectorEntityPassengers.class | Bin 2312 -> 0 bytes ...onverters_1_13_R2_2$DataInspectorItem.class | Bin 1316 -> 0 bytes ...rters_1_13_R2_2$DataInspectorItemList.class | Bin 1326 -> 0 bytes ...rs_1_13_R2_2$DataInspectorLevelPlayer.class | Bin 1792 -> 0 bytes ..._R2_2$DataInspectorMobSpawnerMinecart.class | Bin 2500 -> 0 bytes ...1_13_R2_2$DataInspectorMobSpawnerMobs.class | Bin 2702 -> 0 bytes ...verters_1_13_R2_2$DataInspectorPlayer.class | Bin 1996 -> 0 bytes ..._1_13_R2_2$DataInspectorPlayerVehicle.class | Bin 1965 -> 0 bytes ...ters_1_13_R2_2$DataInspectorStructure.class | Bin 2405 -> 0 bytes ...verters_1_13_R2_2$DataInspectorTagged.class | Bin 1491 -> 0 bytes ...ters_1_13_R2_2$DataInspectorVillagers.class | Bin 2662 -> 0 bytes .../DataConverters_1_13_R2_2$LegacyType.class | Bin 3121 -> 0 bytes ...Converters_1_13_R2_2$WrappedDataFixer.class | Bin 4486 -> 0 bytes .../impl/DataConverters_1_13_R2_2.class | Bin 26822 -> 0 bytes .../impl/DataConverters_1_14_R2$1.class | Bin 294 -> 0 bytes .../DataConverters_1_14_R2$DataConverter.class | Bin 440 -> 0 bytes ...rters_1_14_R2$DataConverterArmorStand.class | Bin 1352 -> 0 bytes ...onverters_1_14_R2$DataConverterBanner.class | Bin 2169 -> 0 bytes ...verters_1_14_R2$DataConverterBedBlock.class | Bin 2992 -> 0 bytes ...nverters_1_14_R2$DataConverterBedItem.class | Bin 1464 -> 0 bytes ...aConverters_1_14_R2$DataConverterBook.class | Bin 3369 -> 0 bytes ...rters_1_14_R2$DataConverterCookedFish.class | Bin 1576 -> 0 bytes ...ters_1_14_R2$DataConverterDropChances.class | Bin 1587 -> 0 bytes ...onverters_1_14_R2$DataConverterEntity.class | Bin 5985 -> 0 bytes ...erters_1_14_R2$DataConverterEquipment.class | Bin 2356 -> 0 bytes ...verters_1_14_R2$DataConverterGuardian.class | Bin 1422 -> 0 bytes ...nverters_1_14_R2$DataConverterHanging.class | Bin 2209 -> 0 bytes ...onverters_1_14_R2$DataConverterHealth.class | Bin 2438 -> 0 bytes ...Converters_1_14_R2$DataConverterHorse.class | Bin 1602 -> 0 bytes ...aConverters_1_14_R2$DataConverterLang.class | Bin 1393 -> 0 bytes ...rters_1_14_R2$DataConverterMaterialId.class | Bin 13785 -> 0 bytes ...verters_1_14_R2$DataConverterMinecart.class | Bin 2029 -> 0 bytes ...rters_1_14_R2$DataConverterMobSpawner.class | Bin 2430 -> 0 bytes ...verters_1_14_R2$DataConverterPotionId.class | Bin 4579 -> 0 bytes ...ters_1_14_R2$DataConverterPotionWater.class | Bin 1855 -> 0 bytes ...onverters_1_14_R2$DataConverterRiding.class | Bin 1944 -> 0 bytes ...onverters_1_14_R2$DataConverterSaddle.class | Bin 1806 -> 0 bytes ...nverters_1_14_R2$DataConverterShulker.class | Bin 1337 -> 0 bytes ..._1_14_R2$DataConverterShulkerBoxBlock.class | Bin 1296 -> 0 bytes ...s_1_14_R2$DataConverterShulkerBoxItem.class | Bin 2716 -> 0 bytes ...rters_1_14_R2$DataConverterSignText$1.class | Bin 2809 -> 0 bytes ...verters_1_14_R2$DataConverterSignText.class | Bin 3121 -> 0 bytes ...verters_1_14_R2$DataConverterSkeleton.class | Bin 1539 -> 0 bytes ...verters_1_14_R2$DataConverterSpawnEgg.class | Bin 3852 -> 0 bytes ...rters_1_14_R2$DataConverterTileEntity.class | Bin 2979 -> 0 bytes ...Converters_1_14_R2$DataConverterTotem.class | Bin 1308 -> 0 bytes ...aConverters_1_14_R2$DataConverterUUID.class | Bin 1314 -> 0 bytes ...taConverters_1_14_R2$DataConverterVBO.class | Bin 1092 -> 0 bytes ...onverters_1_14_R2$DataConverterZombie.class | Bin 1945 -> 0 bytes ...rters_1_14_R2$DataConverterZombieType.class | Bin 1608 -> 0 bytes .../DataConverters_1_14_R2$DataInspector.class | Bin 411 -> 0 bytes ...ters_1_14_R2$DataInspectorBlockEntity.class | Bin 6385 -> 0 bytes ...onverters_1_14_R2$DataInspectorChunks.class | Bin 2574 -> 0 bytes ...ers_1_14_R2$DataInspectorCommandBlock.class | Bin 2286 -> 0 bytes ...onverters_1_14_R2$DataInspectorEntity.class | Bin 2660 -> 0 bytes ...1_14_R2$DataInspectorEntityPassengers.class | Bin 2290 -> 0 bytes ...aConverters_1_14_R2$DataInspectorItem.class | Bin 1306 -> 0 bytes ...verters_1_14_R2$DataInspectorItemList.class | Bin 1316 -> 0 bytes ...ters_1_14_R2$DataInspectorLevelPlayer.class | Bin 1770 -> 0 bytes ...14_R2$DataInspectorMobSpawnerMinecart.class | Bin 2478 -> 0 bytes ...s_1_14_R2$DataInspectorMobSpawnerMobs.class | Bin 2680 -> 0 bytes ...onverters_1_14_R2$DataInspectorPlayer.class | Bin 1974 -> 0 bytes ...rs_1_14_R2$DataInspectorPlayerVehicle.class | Bin 1943 -> 0 bytes ...erters_1_14_R2$DataInspectorStructure.class | Bin 2383 -> 0 bytes ...onverters_1_14_R2$DataInspectorTagged.class | Bin 1481 -> 0 bytes ...erters_1_14_R2$DataInspectorVillagers.class | Bin 2646 -> 0 bytes .../DataConverters_1_14_R2$LegacyType.class | Bin 3150 -> 0 bytes ...taConverters_1_14_R2$WrappedDataFixer.class | Bin 4454 -> 0 bytes .../adapter/impl/DataConverters_1_14_R2.class | Bin 26701 -> 0 bytes .../adapter/impl/Spigot_v1_13_R1$1.class | Bin 959 -> 0 bytes .../bukkit/adapter/impl/Spigot_v1_13_R1.class | Bin 25718 -> 0 bytes .../adapter/impl/Spigot_v1_13_R2$1.class | Bin 959 -> 0 bytes .../bukkit/adapter/impl/Spigot_v1_13_R2.class | Bin 25833 -> 0 bytes .../adapter/impl/Spigot_v1_13_R2_2$1.class | Bin 965 -> 0 bytes .../adapter/impl/Spigot_v1_13_R2_2.class | Bin 26343 -> 0 bytes .../adapter/impl/Spigot_v1_14_R1$1.class | Bin 959 -> 0 bytes .../bukkit/adapter/impl/Spigot_v1_14_R1.class | Bin 26195 -> 0 bytes .../adapter/impl/Spigot_v1_14_R2$1.class | Bin 959 -> 0 bytes .../bukkit/adapter/impl/Spigot_v1_14_R2.class | Bin 26948 -> 0 bytes .../src/main/resources/worldedit-adapters.jar | Bin 0 -> 444681 bytes 122 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverter.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterArmorStand.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBanner.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedBlock.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedItem.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBook.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterCookedFish.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterDropChances.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterEntity.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterEquipment.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterGuardian.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHanging.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHealth.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHorse.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterLang.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMaterialId.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMinecart.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMobSpawner.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterPotionId.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterPotionWater.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterRiding.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSaddle.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterShulker.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterShulkerBoxBlock.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterShulkerBoxItem.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSignText$1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSignText.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSkeleton.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSpawnEgg.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTileEntity.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTotem.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterUUID.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterVBO.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombie.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombieType.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspector.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorBlockEntity.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorChunks.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorCommandBlock.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntity.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntityPassengers.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorItem.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorItemList.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorLevelPlayer.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorMobSpawnerMinecart.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorMobSpawnerMobs.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayer.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayerVehicle.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorStructure.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorTagged.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorVillagers.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$LegacyType.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$WrappedDataFixer.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverter.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterArmorStand.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBanner.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBedBlock.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBedItem.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBook.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterCookedFish.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterDropChances.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEntity.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEquipment.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterGuardian.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHanging.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHealth.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHorse.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterLang.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMaterialId.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMinecart.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMobSpawner.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterPotionId.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterPotionWater.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterRiding.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSaddle.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterShulker.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterShulkerBoxBlock.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterShulkerBoxItem.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSignText$1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSignText.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSkeleton.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSpawnEgg.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTileEntity.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTotem.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterUUID.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterVBO.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombie.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombieType.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspector.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorBlockEntity.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorChunks.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorCommandBlock.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntity.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntityPassengers.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorItem.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorItemList.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorLevelPlayer.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorMobSpawnerMinecart.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorMobSpawnerMobs.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorPlayer.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorPlayerVehicle.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorStructure.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorTagged.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorVillagers.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$LegacyType.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$WrappedDataFixer.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1$1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2$1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2_2.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1$1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R2$1.class delete mode 100644 worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R2.class create mode 100644 worldedit-bukkit/src/main/resources/worldedit-adapters.jar diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index b771a1aa7..21b5bdebb 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -26,14 +26,13 @@ dependencies { } processResources { - from (sourceSets.main.resources.srcDirs) { + filesMatching('plugin.yml') { expand 'internalVersion': project.internalVersion - include 'plugin.yml' - } - - from (sourceSets.main.resources.srcDirs) { - exclude 'plugin.yml' } + from (zipTree('src/main/resources/worldedit-adapters.jar').matching { + exclude 'META-INF/' + }) + exclude '**/worldedit-adapters.jar' } jar { diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$1.class deleted file mode 100644 index a4b5d0ff852132c361b7f085b65cc5992df9f189..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 300 zcmbu4K~4fe5Ji6}Iyjg(7cgPr+Rh*g*bxB}7ls55FllBgI84(G-3{K21qa|zhT;IO ztV;ctN-F=S&cDYKfId12k^~Qgbm8{Coy-Ya^qYkkm! zr>QNC3$I;!QqX#~2`TX9nLW^2@6<}W$n@zYxN xW1~ahK*+9n%4oY%v*nu0NErP$ChLN5Bi~=^RvNOka3^fxUbHQf$_)vTwJ*gsQ!D@g diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverter.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverter.class deleted file mode 100644 index acd6dba8e13643a4757987f27ab7e13e8ab7e83a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 446 zcmbtR!AiqG5Pef?V`E$W0dF4Ki%Y8q#fumb3Q|FfN5eK5Lz-kaZZ`4XJoo{Al((owIXbcCv$=qY1Oc?g!}Q8Vk?SN zab)C!6%`xDh-Mm255t?8Se!4HG6{51>RQF8lfSJK{99d{h%eKe345)V;8WW<3cp0c z*}+;i(!+?bh;$*U?D*tSJZY219H&;S>MV00V_8~fE-lJj{B~;p8$lTU=m&G9*aW$( zDy|5-t+L3aO2qYQ&5_IG?7tRz1VYDs0_b#I=I8Y+@ILAm1`d6POg!WvFZy0f$WX{N>H4x9a?fJWHat(rqQiqgkl}90^j#yUFR$zy zFMa7)!m>l7+N{@!aEmtxZrE4Ti!= zVT05xv%bk2-L9s~ep8y_ksbAYs;}UlP89Zdi)$Ff5JUR75ezZgQekMgiFp+Z8Wyoc zV=j|7FVt`gw@KRMvM!{CJ6Kk+!tnHe&4pnk%F}STS2G@0_kEgdJ^QPLv(rs}Kf2%8Z5P43X1kM%m~RK1$pr8!Zcb>DXcr}gYJ zI*LR_2`OB^MWg?t0lm=&f7?DxBl=Cy^Q3=9oIYA2l7@*hh%%xBvtPhI6BEM-ory@P zyuv8)TE_r7#zTM8;VL$-e6jJi;VKF9cR4bs~d;B;yflP(uFpP aW$1dUo!~{BA*z#{#wiXAQ^aoQD>5S&pCTOf9IUt-~amcHvlhT zA&w_7s35IiC{Fy#alC?86`YaGS$PaA7*TLe!FkDz%Hx89iwa(oWG0R=j4POs_a!NL zT^?`5a5;u6G2|Gc=S>My=9CPE)|_b@Q_Gct;pRobB8irBio%)|t||G3 zko$|K$Ivz|d@<(OD~9VEZbsO);WDUMd5>Ab^9)j&%@v)B?k$};drMz+T&rZ1OkXc7 zFD=m}N}@`px>>1OdXqPAZg6gJXzpryF5TVqpdMy~;Yiu=<&#;%^-RYOD#Rie6s+L$Iot)#+qxbPa3^!EF;RG2Z zQ`D~>8E#&MKtV+jlmPk4{~r@ZCCl=4OW0+7x^UAdQj@3t+ep-#ChQsd4l=O}EwlqO zzH8b9?8#*ApM>i|8tGl4rn~vDEdZgz%E%l=Ct{7|63;DGwA%1M9 zS|e6g>K&qlwuY1;vxnM&w@i^WE;=s3-;~`}i8OSIx2>{QW;5~)7b7=v`xq|lkyUno zX*Je2xt}i8gK^LNkO1pQQiMHv5p|7oM^SKfM@YMaSSiu1f9}&fNp8b zkA}OyqkE_A$2)BKwrw|FtlP3OI7I<|(n2XMTm!EmvVpHtS~L-_A+~|fh^#@G?9*Br zl8=Za$yC1+QQW9PZPOG?Yh(B;{e=$+gx5*^$dr0j<=K7>;yC zYBUI4E(kC*U+(nmLOt#U!4gOYENxa*5Lr9%h0I!PteKlp^JZt z6yHFae~$C~J|_7CT;mThPcbb1C06+(+~HqgoqvOS{4pNzZ}EtKkH`E6Z1SH2v_=V$ zRcg*joI(WiIE^HF2&Xh|qnD^Ky0DHEQ6Y(3164`&k&L0Aq^$`5iS-x;=%@Wb%?nYF YWou58F(}~>%|aH>Ax_hf#bmVQZ@b$%*8l(j diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedBlock.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedBlock.class deleted file mode 100644 index 45b1ab20b47f84c877d85e6f08f33b58eabc3bc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3023 zcmcImS!`QH6g^`*eq-llGZ-)hVkpq0ZQ>?{&?cn?rv(B|3M5Szmh{VIx4YQVvAz8N^A?`CfuxsTO@8(i(?Yo6*V-Z z6{UVgBCA+aVqDRj#108dX-#OD451Zyi9$VW6vLRpP7SUGPs6l;Fa*v|6`fqdm@+au z%tXGJ%UO0#(Mu*0Db7r%PawF)vMq0|fWNJMR3Ok_%$fpCDa$s8rVDA)88Om%u0&GB zjFBHT981mT7X#i7%N2;OH$0=iXwR6AXF5qUo6Hw8lLGpHZJSPi-f&%$Vp~#~Vj%Q=$jbn}&MPttN z)ZVD+xK`1wL^B|uWvYh~xV0^1n_i;8uriJ@?j>B);c*i)^R^R1$&nEw*Iz756{qcN zU;C+v3;3)qCY?Tg6J&go9GdL3=NUN$U9q`Rpz~C%iu|9WuVmkC)@S zi4(z$|G}j?lErUAAY466-f}&Gr3*Soin7dY{qLHz7cxs3bIPkEIhvXbkHYY9aoWk4S6K>k z=bm)kC*Yt{`PFeDE@BQ+=8T!wQNnKeEL~r8bwZvORFUv_u+mr zJfWD?@ctGAF`gx;$E{MFSdXVwRk_RKc@=Pcyyz4RFJ3Tq z$J1uKV7V@p%{ghfW?wsdN$WqnX)OF*hQlYIX3X@t`0or18n(fQkrAsa ztUQv`Xlq}1wH>XwDRM-&F^g03ixj#z>j^7D;JYXkP6berLRN0LdJ(B9D{06 zeu6ggdQ|}JSk9S12Rb<_Wkr>8pe10wNP42~rzhwJj_W3{qN?kA9(8D;&S!zkmqmPK z_=h?ofimiP0v(Z{qIDe+tvOtV>X=Q|;!wWGjD$A(v4aGtcy^MyQ zFqy_OntJQ~J$h7+)xYx`N-g5qSbbDq*@C&fTIpFBQN6ioZ%+e>oK;+7RM#p@)7xm? z`Z`*An`6z9NaVCKPA3zMHbetjX?q!GaCT<2F&aKTJ1g20t(%_(W6fp6Ht*BL{<-`1 zNse3gqjBg}EQ*}-CeHO?*~<*whl4o8yYN@iY-17Ad;~uEIYROaw8$?JlV4%6{2Cqd z8}!O=(J#M4N`8+`@&{~}KVql+2_^Y6?v}scVfibbmPhf7oWp?-@McKhy^s$dQ1&D0 z9}Gzx3I%aEq~S;?T)C1mB7B=RqYK?=;Bz#HmE;=P-q-V=W;dGfH2QEUdieiv3-;hL zuIcE-vHt}ie!y44{QV-yA%1Q2jh_#gS^K#$EI<5r}!@IbGTpjWE z2ChVs@an)zw3&p4!?d&>8>m4r%mYPnSJ8^f*AZNeYe)yUZ$q1-Ge&c*hUjA!HVN@=Y?9njvud9PuSsui{_j@4TE bm`A*xGaqiiGSUdSRybJ7@XjZl35I?H#25q^ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedItem.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBedItem.class deleted file mode 100644 index 96ccc83d0162ae41ec7c699dce918a7100a6d7e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1474 zcmcIk-A)rx5dKbEx@}pYlz$OLtZ5h<87shCj2#0#6#-D6q0KV`c`-@_|? z1~1f$nt0&@_)x~#w$?T#8lqn8nKN_doB3wW?D_ib^A`YXco2b%*$}RUa6N(>h(~Y} zb0N%oN+OIT79zByJath*T7n|s7DI4Lw{&-#!JkMTGX%1>CK!hDx+MO_H>-xy6RuWVE-tSY4_AsS@t%Wro(#iaS-9TOv2bd- zZ8dAjF-U5Q62tRE-V&~2Qc2CeF-}ZPyWl@Fho7Biovb2^0;&=RF~o4 z-=?A-^fZcL@gjH45T@xVxQ=d>8RioCpM+aR8irp?J$3!S2E|#O8#L%+-9cJaXOhnt zLSCX1+o2xxxctadV3_|s^?j>uW^KcEXyOj{_Za>(s2u?PB?FYc3C>xXctvz-9XjLP zjN5by-gB_?w|9kE^wYyc+3A(?(??TFT9kGQNk+17;S<;g+W0U`YtS=>qlnSo1Cj$q zFiw(T0+Y0Q;513^EHE4p??`rIN4l_q4t5Hc+Sm#a@eyV&=1ax=4FnqKdxNP|EZBhb z7E#)KM5uxA>jomJ_vGnsG8^;?2v1-lJc)RCx|wCX6{($tVqzMXDbGw3#o}~)rAhB9 U#z@9U@5d5G5uuJOVL2H74igf7?f?J) diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBook.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterBook.class deleted file mode 100644 index 114a2617e1012ffb8ec752d8da6deaf6c17858c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3342 zcmb_fTWl0n82(PXduF=~y{z5pau*S{^fD9#q2=0zLZK9BOA%D+?Cx|sbUL%lPRmWa z;sw0D0xu8~f-yd*38eueCK^m3DiI@wV2lQ1f)6A{6EP9}&+gLh(ppO7VbA41|NZ~Y ze`e3!JoPbvNAQ*xQ&8(c$b;oxtU#R?E3wLhda+sU!5T3)h+(Z4jaVm!^&V{Sq6y7{ zw?zyaCA4}`giU#P44Wlv@#1kj;lYyQbZX}wBgZA*(93t3%ptJ{p$l-?aX1Eb)44cpWnRWVdErZhXYZpO$p zZiTmL5hwd}U6Mwpj8f0YQ?D6z95rU>3F4eND&q~rOBxDNl9bk@=T!`qqY@tom68?d ziZhIDcGO7cS~Z?5s)SAnhJ>ypK(>;H%~rP^(du-8f{9s0$f!=G$bgKgc!;57AlubD zY~67*vn`y&M2;RM^)gIYWI#q7+sO$EUxp3JqdTs~w1f-?-71Ryqc%0uY0-8%!q4X|>ZUvUt6auT>M; zfDQ>S3DK7sz%Z36pu{XIW@t(*VVTNm8rG|JLR+yjqQxD8rG!@m|9;{4ek$|G_ELyU z;Yf%bkntK`7sDG8-ehPJ2Jh`nVkjI$a0;UgjrZ0L0WAwW4CSNALo(@fGZ})TVHcMp zE1Fau8S$4qhi$zT=`2kA_ud?z2O z%=^5O?lbk<%8`>Gn#6LAUKd?8D4CRt#^CU(h5{{vl6)|0wq%xJ;LTVvvIj%^)HLB# zbB0U#w-f4yfzF)}JJb$khZNndcl6c{Hk~w1=s8GeRG|&Q`a9^OE-8BQXddh&AH%|7 zVjZm!LgUi^i$?nDn@m532kA2~mwxnE(ry~96q@NVfqUjjun%aFgNJG4g2+F@bXv

G-t}5$&hso$W|m}NH(VqZg@!DWM591FSi%2Ubqi2 zUzv~hLRwqy^AzUwBJU9OYFc`F;cd*F=kmKMdNJm0T&?gEzg+ER)!a8W;3nC_cqicQ zL;hhL4Y)~PLE+S+C=R&AVWBIUBpg9S`fShbXM2yJ=roEp2izy&tLDd{eTe%4ZeOvh z5B_Q%;GZL3ocl`B=k97r5DSFS2ZTT-A&^0skfk-8>i;0`| zx!Cc40u(icI;re^s@FlBKp*bM8JtBw%@=S9mub#TmTEU9QK>#fKK~4Ueil>6t5V*N zx%?a!@$*>9zd#fJ5(oHKILN=oF@6#6@^5g0e}_K)El%;vIK!{tEdK%h{Ck||Kj8wu zic9<#T;@OH3crRQ`LDRnuj4QN8!P1ftc3r;Ch{A}60d@UMYu>vnnfjDO5RmrHUX#{ z*D#0vbhuE8-!T{S$X`G6;8Dycpitq{pb)DCL}REX2q`GIiE;@w5*D(*v5a&}SUi60 zgjxwpSmVIp^ZtqPH^@v5nH0!dMrH)CT?F-Z1mPvHw__U@e^T1<0`1#Sj8~EOFV+^U AVgLXD diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterCookedFish.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterCookedFish.class deleted file mode 100644 index f856571ebefb2ff07fd044987cd8eeeb7c7e6e11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1586 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 biR0~R5f0-r%^}jyVGfrNpt7ICJzw)*&)!Zk diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterGuardian.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterGuardian.class deleted file mode 100644 index 2e02686059bfe3410f4c3edd5d344351abfa98ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1432 zcmcIk+foxj5IvLICSkcn0Ywp1E(yV`TvRYfS;R|G6;T0GlnE53C`Rm&c0BhKaL&Z!KH>0=}$8F5UF^Bmm z7NnAlA|>UbT+#~eD99+#7$TddZTedb!DOny5Xw1*U>MGuw%Dy#OTsj@=NhFWl#K?iwby8Ppxy7H-bso+rrdFt0mR&8w_$9BUsP z*D{1*`dX=8sgU3XuMt=?t2ImOi{}-Wi_5FUy_Mq1Y~MjQQI=t-EPQ!Z5UyuBl$xs9 zVNmooDTa5+ye)jKN@eLTfA4FaaEY$g=)~4`w+{|@IpMcW@5^Xz1^Ysq07hwzNTafY1nnh|9B>KaBpD`fg;oj9kd$Yk(ZKglBzv*>9&G3odli!% zY@LV%2(yp~q!Ym=LQRBEFquw7nov$KK*mJ0iCD`JPk$!YV2j!~QGxObL&|GRD0`Sz y-e68SY^57-hwP-I;JAkClyFLtL|{5h=QmnJr!ht{LHYoea2avx%@XcLV!r`}Tyh2g diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHanging.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHanging.class deleted file mode 100644 index 95251492de42c83f039b0233b4ec18437a419eb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2219 zcmcIlZBrXn6n-vA?k?$;#uZRhtS>bZLfJxJY)h>)P$V`$g_O2b8!nqoSd!fhn++XC z$6w$VXZ+HB(2t$YI8*%+9Uc7v{v>reo|`OfVzG>)&TMjC?m6c0~J>!%}M2g zibYA6R9uzH4;8E^$Sb(Uz%SUY9b9CHjHFf>qBCC6VmOksU2C!7Y*>C?Y*b03=R8wX zSA}m&IaEf2O}oy}KPv(;XvhXXXrtEw|wm zZQnA3RszQl2ymIqXZOshf{5wV7{(9q`b(A!jM}Q_w#1Gws?>F3CGe^96fat;3Yq|0 zV~9z1f>K-wgjrb-wbtwuTvu>|A->`@eAAk<<&1~B`rFa?aS5T}6$~@<*hK|5HLT$l zgL+liZa|n6Ps2y}n4vctSk9a;916(igh_`QZlgdak1N)&4ng=DHegbUd4eaQ2uni= zNeyLehH65xkqm`34O{ZKf~s6E0$TP0AzQA&fgC(RXz-9!K>fV-zbqU>;z`GsHnwQy z42%CQ6pgEE7G0R_DKn&>z0+Mg#xVA5>+ap6VbPu114@oOy<@4TRWxsFyCJHylmnd} z?H)~~Xc@IlQNLpCE|v1THQJBCPP1@%v(io>^vrHRCS8$2lT?QCEBT%yqf9cK7|9-V zW4oF`7lac))}_Ji8=qbt8W~(FZVA(J1G*=?9@_7pGQBxF9d34uR1o(q$J_b4ddOWN zfOf_EA!OvcS*MgHXZJRKRa6@kZ~EUZ9$v!`eR3FHrteRLess%8dX+eXC?gsh{T}Q) zVtR0t{<&208{`ORZ3DcHVZLxPzCANw94>)u_mew_T znm9ZZYoc$xi6dz}K~Jc8uC3A2x*lqtZ)+$(zeJcw>jPofB(d~Rge_DUx z2@tWQP$bZc@;v>mti9E*3=-6@0u;WEJ}xlGO^osqPV+LR`6iaRjUwN|4zJ)-Ud89! z!B@P72Yee3d4QkzomRuYlxeX%v2uBs1WbAi*_6HIQPW^^M?k^<-LCb DHr6}2 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHealth.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterHealth.class deleted file mode 100644 index 2743b71e937c887dca8d5e06d3f3a203fc5feb20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2448 zcmcIlNpl-T6#hoGM{QY-op$y;aWLMJiJgSR*o4GNybv!TV;qz~%t#tb6OCq+(a6RD z!oKg@A^ZU@90F9Cr3wxlIr2032^2-~wIm0tl1mCGmA?17`@Pq1>o>pt_2bU~j^Xnd z1~Ao(BbXMLiD4EOTJSh73Ycm!r{D<%^8%L?eKLxqz-56e0#6A%EpSy}LEsqyOCTkX z7RU(L0*eA!ft-LNa7`dD;0hE3JON*zC~#dM5GVY#;ZxMm zM;y-yPibiA?wQxnnD8^yZJTmDd!}4S*}>%MiMqTR$ zJ&Gl)CEF}I89QLY6FDcHw^acW{<2yJwp~;wE$2K+oDHn3DvzkF3KrSsD(i%_MWN6M zS0?V%~9GE32%uuCe33YZs_}$qCam7$eQu!Kh#28)&@byX+Oc>QxjU$MFe1 zjp8#6bN|QdsH^8}>YANq24?=-n;3dsUux*TpV!7R@%>f@l7_DCyQfso-CMk~Zt}4b zeC?s-cuex<^){+O5BFT=JYq+kw^wEt=T?gBh%M{IY6Edn$qD*1=K8A7>rB;Tdic=w zz%KYpG;&V?j!{v%W8+@;jHyw(N7W(g`&rjE$QFE$#C2ICHOv`E%(Is#tWu6E4c*;W z*5zR>tm;srNf* zUspsPChBTa@5C_qcvS!+c$6!;hciT_e27#jH?$YNB8lK1)vk4_4R=&Wk*KNuf(HJ8 z$!`$plMSnA`~gi7+`>?w)Z5dmh~7d6*;S643TgflTl-|Ja`Xk7`fhVkJ&YY(MN8jp z8B%_zCf3gKRaEjdFvTY?5teQkU&! zGAcKkNg<_~Y}aK6F)B9^h1^VRmRpE1xs})=w-MuVJF!*nAa0O5iEVNhv0d&aZj^h7 zQtl;o$bH03azAmiJV4wcJBeH6LE<*~0CBtQBJPk65_igO;x5@k+%0>Fdt@JRuk0u8 ulZS}=eU;RnM7|(21ZG$gF-DKu`bLM*6IzW%^=%%UtBo}RCj%OpfmREen@m8z*XIdc~V7Y0u(TpL;#I@q+~pEAmj zC`nIk%uB~LY|GDMhJhFA;V|4zWi09G6-ub!h&!I{N{0f~7X!z7_Tt=}D5dR6)vj5^ z(cX=jGcbb&9T_fEstf}grMKriQ7F%fYEaWy&aOEHIc=z_?`g`pp%?@A#G;5JiOmdc zQ99(bzs{~ zyOK9#;Hy1XmZtPeaplT`+1HaL3utwf!@WE!f9boBpx9)Bs{1pF# z59&ird?4{b6a7)fGo?rycp;MP&Y3gkeCK>~=FI&5^X&-0BAzCZz=(l6NsMAl4R;f` zhxHE!-^; zI7)9VYSFF}G7P>Hk;wVpz6>H6Si;+3FxNa!202%Rp(K}rW&2egR+g6E^8-I{%d+f5 zyi~7LNQkni5s*98n#((4g~hqz+(L0QF3&zJV39Wkt5ZXSl-j!H1hT;wpR33o;KS{~-N3x_qT>u}mS z<-8dM4)xGl<}E{l+UQtkm^jBNa~5~9|9a%Oym>b$fwqy)7t~#8rfD-#tG1QvBvnu3 zTmAvv5)l&kByl_J+{B6SlY|oNaH~Yo^o(;xe(8I!zq*o?JKeZugy)@$_8OiRc zuV9~P(uF=6<7&}3LO;!wD>+~QS4c8k#So1OoF%Dj+F)$PY z`2(ZVsjdN|f!GHO(UiUhv@hsxAl`sJ{fS&+O-g-=x$y%%#!q@8e>KAoABSj#r(n2_ g8ayp*)3tbX#F#rGn diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMaterialId.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMaterialId.class deleted file mode 100644 index 4a6daf619ccbda05231e7e36914e4f86dbdf4bc6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13795 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMobSpawner.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterMobSpawner.class deleted file mode 100644 index ac0c7ac793e6a5c4201ab19d3351c8f58c0d8f64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2400 zcmcIlT~ixX7=BJRo86>ah-;x@MQdBzga9iaY70m!DV4P0qmW`nY1|}BSd#3fy9*t9 zTmOKU?Ona87mkB7PMqn5KfwRtj2AlUs53Iv;(Inhh%h6Jda>uc=bYz#-p_OP>!**u z0x*b51jlh+#swKe5e#D_f;TZL<04;NlJORw$M|Ma#$~=3=ff2~ye(sbHm;u;^) zGA3nA$(WXKUBaw{Ifl@PX_?+AgAj|)GX#@%!C+`jo0c)PTFDtsM$eULM@`##y*#fw zCSNx;gWj^~G916GdwSBg)(popoJl)3SJm%WhQpwwESi&L-E|EDE~N8zMRQB%FWlDd z*iN}%6iiRct(HnO=>@$?>Y7=pmbE5EH`|x(8_3S~XZz1I9qgDIW@srI9zUHo9M`lh zKcWWiom(X;-TDs#O?{9}dpIC`2{A zqOa*%S+|PXoadNUkz8xFa-OFbDR`f`kD>Rl+<&7O*hAV+_D%XIpXIt^-+0 z6P6qm@|7yX(K%1gmnQY9UuM5qZb+Dy@D6d$*{e?8xMK3A=xnOSt}^xVBq->>^Q5s; zC5C`mkZ?o6O}tBt3KsAlgFJ3|rnjCdD0m->3}L^2IJbgZ$SU{%I{7wZ78T@>S5SbV zUdQAPd)~H%dMPTSYOp`acSnpSc*g+V0$55&0(rv4qjqUCI_}(o_zHxh% zYQ@mDTce(!;rIeQ8_T+T%~+pas#mUkH>`1~QXF@LtZ!dehOvEMhrYv->5f;b-n##M zkcqIn6X3ah4D5}MKcfO^F^ueo|Hs^p>8>%%NkWcMvDc_`o6^*Xp93Tczg~um`&ddH zEcV9D54z@EGSwG5pxSoY>Cw3KZ#x<%(M~@)hUe(7C(uXl2CYtzq|wZ17Q4O#`<#RT zUZ63=H^pzzNwQK0;6=PlD~3}zO(R$Cp_wZS(bA_h?NKVLJS7nb8BqP9v z8c3)@4Z#}32M`k*2{jazYmn}vk3>3{OsKRDPxYumcMXyIkkuoP5F}Zllb#xm`nZ;a z+8Pb}ii=!~)DWE%Mmq`j%*VLe-C2V=6zmA9&u-I`e2j>P#12sv_<`?*LQ-3YNVN5> zmO8BELxDZo`XaHx!}U`%i({0c@6aNCkEr+qPKZC^l=u_k;?Ecne?e0G6)EvIWW-G@ zice4!e}^SL#a(d=_d*OGg#vgG67Vn-#3ywASt#u1Y!))5_#DpC7eE{*5u;JSJ<44d zNg^x^Awg0QSxlpw${=77*U?MW4Dg&b^3A1J2}fN=yAzP2Tf`ZZ&@W*?!XS+Z)Wt0V uG#?1tn88i7{(&|LudyeX*d+S_yiV`{-XPxqm85pe;3Y(;zh;mLh5rOVAa#fU diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterPotionId.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterPotionId.class deleted file mode 100644 index 213f0f4e58d6cc838ec2a4db6688de94f8646348..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4550 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 Xi0Y8SRiXy%lgMBQ3F0$&*xmCl;n(LS diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterRiding.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterRiding.class deleted file mode 100644 index 94c5c8e9b2c82f8e175212ee97e5e96967e8d4d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1936 zcmcIl>uwWA6#gbQv&Pvti6IFgAq7fX$9A&h!mUoZ#1tvQ2^Dcu!4IslJ#jX%cg^l5 z2ws3^0Er(|E%ZkOL8wLoi3jM5^et%5tQRMiA~jZ9S$k%7=A83==eGXi)BBGAX7PO# zF(e`wk0Oaw6g@~QF`;2H3XX&lMg(Wo^^_9RO3Y|Dr{TPY3k-bDv`p_ZLntx6!Vu2d zWy#Q+GcCEaSu08>FN#$>#;-&k>1KX*VW!dzM;^xK%Eut*yWNMhTdevz2<`$+3Q!|Cz z(}n3XZ5K_L3`49UJ$17p9oMuiKavFot<)sMa4(Uwq-WG9q>>|6J;Rj_Q8l&#&&JYx zJ})X+yH>Y1t#W3(Gj+L1%y(u5wTFpPKQ(XoVxn0i7o82^`q0Ke(@$UGL-bHP(_5T&2CYn;Cf|X*p-mT#kmTx+KgChn>rDj=;26Cz4C6RS zWjsl%G7k6S@iwh{ZJ+J24YzDZFdEoCLWq9ASSsGt7i}Q)1V@vp2EvQURJwsf>Dqc&{rndU@n12_UtpB~<|CaXy?#V+0%OF3{05k6_XRzSl0Z!9 zZiFNaZNOul?80<2_yPRRJ7`N2L?ZH2I(~Sff#_~V;!2BeBf?)H#$RKA@A$aMrgaN# z5T|`K@)&T5Q0l+L86Stf7y<5-p4OYt|*z34A`S_RxpV@zH1x6t_S=;4i4kYv&V h>kYuPR^VOu+V}7chG>nGuO9mE9YmC@W^s`p{u=~8<5mCw diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSaddle.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSaddle.class deleted file mode 100644 index 865101fd6e5027bd45d889fc9ff4c55bb14ad291..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1777 zcmcIl?QRoC6g^`nyPM4d=@KZk(9%F5iA}cofFwAj!441;e?aV7DnE$E_TX&d-8H-8 zRCyHo4E<3gWF#u}0s2ans@}03utlmWD*W)=nY-uQd+wbN|M~aZKL9MDV&WWT4I~UC zO_;c8Vh)ah@6=-6z=E=iI+m0r+%08q8(3C$#lWhvchrzl!%MbD?z$1f*$pmvCh!kLC`DM} z^}1qMS>G37rpcp75U7%?1)dY_udKdseh$KBUDRFaRNMReWO$voi0ZgrtLY3yi+1LB z<`;Li7j_n|4SndPNim#m2&ukQL>Re&->oFepx1hW7@ke%d?6i=N~(qYxpX2Cl2qrQ zAK59S%Vplk1YRp>`}Ne!$>7v2zbYkfP<`D1^9*w*4H2(-ErwGi$!q(0-s<<)ECubb zCLXw|pO=TqALz^69zWm~KF0-y@%z4X<>6)!Mns9Zbqi@^bZl6-j|U89uWeZ=JPQx8 zNe7_kv5>_hhU7^)#W3-%sdu98wp-Xjj$t%Ios<^xC{TtC?(v4OP{d;kPq1yFgtCqw z8OopHOpq+q5vR%hhEuHWiJD|6eB4a5S3}#uFh<9)BtzG4FkGL`y;sn4(y98uH6-+i ztBDtF-lPk2ZZJr%jMU6ix>vhA+7gGw=jFo|?eY0RSU*=*;Y<>g4uYoObSH*_9VsHv zSoB`?jbkExC|bP|I z4oJ$eB@$r$|L#1lV3OWnDuf>6IQ{6R(dr`29I}k;=LJ1Tow6v6@DKY&43PlJt2&p2p5(!1(K(ukTi5tgG?MjJL;SwwSn>fwG@aRHh~?d?U>GY{j@WKDE5a-BicOYe!8N(P z%RMX5Lt{+VEuUfX5tlsgI)}oO!YkI>c0+g!`j+DeFK=_-7v%M#V7g7iZ>--vFpgZ$ zu8OK9jY_-GAi=A=MOedXwrpb{oL^opFRzxLt&~^h2M)qK8w{g0A%mk`;rW*9bZgmS zP|O}BhF9r=Bc#!!qD+tPNy8T&ku?s((8l&=sl;n}x7l*rPIV)5I(JHFHd_q2)51oI zlADdEycPCSE4ppZ6pyW-_+*WXh;rV~L5r*-Ap<#2UX6#hh%@Ap$v@=LDl0%E1!9LL@f-zd- zfl-whr@h{Dzyu~qql%HDH2~*G2H@C4H2r~OKlZ2(8~cephw~w}PDCPvnM+2p$!G_$ z4u;+#l}*OS%?_0J7!I~t2Ws{sxkbCQMg#WhYfPzcFsr`prbzX|gefQ>rf`9hT_Hd!r7*kA>CRh_`dZAG=EF;~ryF+Ie^i_NZ zO=_amc;N&1P{x0OR?w?Pz1aQdKYagr=KGJY-vF#(Er|qXOm82%l+1!y9fNW(oRD* z?10xhtrii{5N-0oZMW_45x0JAxwgDod%99vnHy337H^#)-IPISvMaT3E3a4E7K35+ zQ)GCVuXr-xE){8M@hafH)Ra8$4npwljh!9QEGxIII$mSFa5{4eXt`~M(rIDi)j(LS z$D%#xZ?dX7+LD`gIDy%bs)yQ9+814s!WpC(rcP?Q=lAEp5V0EuiYY8&$v`Ouj@t}l zW#uTH!ZKD2tTMd#uR~#&43p%J@S6NdeP3Du!}h-o$uK_BA%?}%44EN8Yf}xh?KK(Z z^Oau-_l2|te~3ovI>yH3K}R^W>C?kb`c4?E`6uN~E|F$!9$xV6y z7?SiFMCqgDAa0yaoG2qYw(uG3105nr(?1>x&G(p~b7)Ein8aD43|UOmKLnSEhPv2P zbm<+@VeH`$Hg#9v8^(#U6@fNqwo8&I~d{GsK&i#}w6{B)Sk!`~>IpRzd&( diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterShulkerBoxItem.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterShulkerBoxItem.class deleted file mode 100644 index cc47a10e71993cc5ee9e3b2fb1ad45c77a9c58ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2726 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSignText.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSignText.class deleted file mode 100644 index eca776466a9d32b36050e43d8106436d9c4b1090..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3133 zcmcIm+fNi%82=qum_6GOaV;vK#S1D6tRqNUWvv(18;WRMq>2`t-90V?voq_=EO@E* zW@7r{la0|dwQqf}54BCel*BZtNt6ChZTg+r1!slQklIc5d~?40`EKX@@z*ae0QBI? z2)3XvjAR%`A~=d;5gf;fF#03djFVxU3S%IQ(_suoa0X{3^+UOwQ;>>aHHJ9xomVg% z!AH0d#zh4q5nRG$xqK{_QK@!J!IcP_(5FC;U?ckECM}nY0-@llf*eD`5#7_1wlyUj zPdF(fXAOz#9)sF%S;9%0y6Xy;f$0qE1~PVD%h`6$6k5);E$uih35MGJhGlpM7^>T1 z!wjLMofQnL2MkLL7V~N04C!f;Fwp@!qnpFJW5|6O8S=&rGH}6H?oRIAcTJnN9WyJk zhNq>AlamDWtX?4RG$UUywF-ybv97VMJ!9v($GTf92=gZ)_v&)OleA&sxQ1={ZuT=M znbN5lM%xA~;c0pDH{(&PQhKBT9(#{v`qLod=R>n>SGx-9;u9b?d zN_l!_^0Zzkhbp;3KL;lCDP1#lE2pJA$FOnW{d0@ zSp^d+CSj6h6?qV{M%H7Oirsj(yy-5(J!RNK3ap|@GPa5WuBmX~s_>vOXv-%yIj(zt zS}kFD(vWnhsA4;IFzjAlwqFYO>8@B%pkPXhPBVaED+RcsSx!>3oYfsy9KD_q1&=CG z!F9=hQ+iFycHC0&32rkqzb-2qt*>ZMS2)xvlKSR5rImtw2cN3=44*6bf?@dovBOaR zsxC`~#4z|~Z85B>sJjZArCwm@Tt2^*P0zq-jLeJfXj|MbvBfCr9&xRxo77+pL5Xtv z#Hep}F7L#7&oGm=X;a!+`ZX={Jxy9_Gvm5*n3^=y)*nmK-V|2O8~+CZ8UnkPH!Dl~ zh@dfO=%#T~7TsXm($jzOp#vEI`bdlfBU3&)!@=b}SlnH$(y3IyrMlM<$AU4QkIugg z-Nkn3#vny2^^PuuS5;lMO*P}bs+pZjc(+(aPUy9c$QdqOctbY|;&AEiW9SdcJL0NI zQ(2Q7iGY^*%33m6TI5v`qtLLgiMyaXZyI)0R~Oq#5R5k?R?O;yRM|WY?rK{8+*udkFSBX6Pa$ak}K>fLQ)-Gc65>-gRD0c zeJf7xJjOTi=TINx>o_^Ms($Nth{lOf7s~qECy12@w<-y@pP+sYt1rf9QQsT-9{NvM z6OTqi&#|^Q)EN35b&?u=yG*X>t?`j$Yn@~d?AHhO%|Vqx4IQ10pc8t5vyi+cp`;{hHLEQM|q>nU{SP|H)`{5%@@FivrL#_|zl`6U?qGCY0-(|i;+ zcp7(j7I%3L_qf1Ud;<5mi3i-qL!QSY?%-SQ;whiT48Mur_$@#DJ${kBTnPV5yyu6X zVvP5(m!e;b7uZK%)!>*zFA|gknVc4=f1+E#egz+FP@C!He1M%^Sk^=k#=(W!?Ij`k zYnnsT#aT2*qjT6uADd?I&J0?9#u{1B%&(X_G6lW`Yxw~>@)mO85Yeh|7_9`ilBUhb XVjJW;UH-y^%VNBi(_=o08{mHfT+=*@ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSkeleton.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSkeleton.class deleted file mode 100644 index bdbbd43b8634ff524aecdb6b523f9272344da345..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1549 zcmcIkSx*yD6#j0v+m>OgA}&->5L%XwEGnCb6irA9CPL8oKyy32mZ7thnJI>!;u~+i z_@FP4nCK7iCz)tG(?#0g3sE0t&OPUz?=0Uv_kR2N`73}~JdL9hBTt_Z%ue2Yg>oX@uag=mWK3fi$PhpEa_wo;kuICUgb2~RNeC2 z{DJz`c8sDd>YiGtmdhkWQB(-5>So1I+v2(Tsr=MT{>5~Ddbn+)nP`!rt0X;tZ$~<= z?x&`1))}}~FN$F|m9wO$n$(u&h&P_fYYjX)0L36NWGq zCXN)WBFnMHu=9V8l%eO0i|2)Xsd)^W|27wK+s0j6&N}}L6Bn5ph8WFZ6FQPQf1c^{ zCc1+1pehXi9fiNF$?-(w1bjIe zIz|`mC88&Yy+=IC;d|)k`xxM5jB*1L+@yE5 zf(7o@Y8s=w{TRXkk~K1x8r4xPxQSa-A3e$##BJ*54rS;>@COCL5L3P*OvYg{25=Ww TNG52dUWG?)s~8M diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSpawnEgg.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterSpawnEgg.class deleted file mode 100644 index 1e45a0d6601adae58a419373cb1377f7f07ca0f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3822 zcmcJRX?PSx8pr>Yq%t+hgoJ{CAPVlXLI^MrkSoYBAqiP>EfW(Kl+ZKNnQ79~J@oVt z!mi?a;f*(f2i|y~TpAPwym8%wz1iE3e)OaJN%pOp1j6w=`|#{;o}_qe_(zX$jn~kt-ILUC-_bew_%TT=7ax8xdL*dk_PLi#26DC7>v*nnrxpd6* zI*gc2E3(;*8+NDRS!zDGSmdWHvRt{s@Qpgx*=%~g=|wX}pHrVqGK88O$MouKBbzlz zY)y0AO^36+3l?q)_qm>(FcX#^j^%oL2}Z)mkaE~cXYBBK_OjixyJyeoUR~2&Gx@w1 zLmN>PBa)`C-gTN@)^Z&kO%p>Po_C62{nTd1^uuWiEAAORemHA-LP{$D?z41_!WK~!YTZQcBkM%_$_|N5Uh86%kQT=l7}mdw2?GJ_&xp*!XNRc5W27? zgwyzQ2!Fv}L--s1&QNh-OHvCq`DU7duW4`dVq~-<<++0m6>K(*Y-*L``V?HdVbOLD z?ZuaSBtlD3$L)(5woStZ%QN%CvS^x?&dnzs?I zWVx4iJ*vOjqbTAUBvjF&THWyc)mFmHAK|j0rMi@vC6V%>c|*=~jJS$pXr-gIgZ3Gk zt#rvdZV4Qx}t4Y0D=AqA_Q93388Oh~}$6 z;^dBUGDR`btWLFFpe|)mMM;iFH{~oeUQBgpi!xW-w$-#%AD4An zwoNC+YjkbZ_vEKKL@Qk{OAZvTHexZ0#Ke#owWfBk&g;+mh8@5^7&_^8`9EB&=N-?s z*hcC~hSvY>UX+0IZX<^2mvd25x#;T8f6W-KoqF*NTy^mhrPbV&Gi)k-<#3IBh_zL8 z`<0Sa>S=vtGem|<4SqT=`wJnIqw3neVAmmgbd!gu-&dLaZ9N_R87lsmOKjVuybET} z#XRK_LKlauzU_si#jyBN^8YdA5hH8XDkDN|osZ&D?nRZ%vj4V4Fp2&jr1&5i#&##XdKE5U_A_)F~kt3r&69lRLX@F z);_{;RdbkX;aSxL%)Bb&D5On*ge<6*g##!W0N;hKYFRu$7v6L!2(8sJIDnFQMKfe! z1uc~B#aOs!*3#Aaq43(m=iA>N> z!8Icpj-lc(LKJL~92q5WDHSRLa+Ic!qcwxFQnN&k(JYl?HAC_W%`!PobA%kPSuU^C ztdJ8lN6M=-rMy~ml$@wJT29iel-FpEk>ArCE5EOKg`BK8PX0i1yu4QPYB@!-N>0_B zCaW~7BzT()T@WV@y*f26rZ zu2vk0FJv^Tjww_9%*LRe`gsF_{5DkZ+cB2kfr3FG3?=wV=sRK`}s~B;ZNcOoy(JaH%{@V zaGF1julO_gnm>zg_#S-ApTimcJPYs_SUG=@jpZ+~iTq_Yg}=hWd@q~NUu8@AYpjvK z&f54Jtc&ks-TY0KS+b>JkrQ9?K2N&KQX_-|61``7>g diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTileEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTileEntity.class deleted file mode 100644 index 314ad9cfb7a5f4b35db770b66ad3f8a3c0fd39cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2989 zcmcImX>b%p6#hC_cb4TEjtB@uMMxlIO#lrfBIE)z36aErsI0xSlg%WvGt10umWcO> zCti4;{Ism{szR|Wi(gt;{;;%)AKr@hiT~B|&F&;KODwA>wNgpX_w~E_z1Oev&Y!Qp z31Br2Mz9u_RH6w30^1|lflH@gCobc-+yhrcunTd4D+Q#-Cj?Z1q<|(cD3B5u63_*P z1x5r6fwX`rU`7j({tW6&MxB3G5LV6SzuXufWv;*9crIaGk*Q0yhZUC~%X& z%>uUw+$wOJz&?T71?~{IQ{XOvy9MsyxR>KTj{6yyWSHJHEJtN5>*_|VTV|RWD*N=5 zDc!8CF{~-xZ7D!QnyFZyYwKpJc`~z}Y*e)9rtYq1D6Od-U?^*|l4Naqmu_l3*>pm) z`(?r)M(MItX$(kP_pncvxkI|cP}MG7*=Cuen(dN;ZfG5*tGie&9E}8b zcBxi6=8QD0-5twWwvp75x*JPmM@DFoNtq$_n4ZoUu_B93ydmDOD!#2T-ngV_BXC70 znU>OAZ+Aem9o;hXC)&cm)k0tlyK1^j&5fn$XsRs--I$}<6mo3Tw;tE@oFY*>00DE6d!fl1kI^IUE87qgglTynrz1thNX@$ zMB2OBHCI#fb`}I~l5)(@Q$ub%IkC&zZ7Y-Ujyf|WH_k;nOm#?_u76MF2O?Tw!#kE+ zxLJ`7Gr38+T29i1nG=>w##7_GCqx&iaNJ@c&5rwNsO&VXoM!i0l%!A=2Jr3@`bpJ~ga#V{zV-it|NHezbI&C(enM0c&mcb$JyeVQJU(oB{@Z3=t! z;|h8Gr{FjI+XAAR{!v*AhIRBi-<#XCo=^YClwdu|Xr*yZ%trc((aLBoU;ZlCOL>u2 z`di_V{3zP!J6aGxJ2nww*o-ao*Hf;i)l)8;S#sogT1yb>@dnpa0C_Ib#Ea;RNW!)6)%!VY2K{jMb6)Y!r#YS{s9*9V|f?V1v9=2 zGKem8lM@9~(SxlNR4>^OV84?JE~c+-d#NLd_!YUPXooT;1@fF;V= z0a&Um3qXxh8-V4?iU8CpD+5rk!~$@R(hz_~WmN!HD{BI9u5w-hc&)|D` z;2&ZZ{|MFmW31$#U>*MyoA_tw=buCJFJSU7v6mmmKK>OB@UL-@e}fnJw|Ikphok&^ z9OFOWIR6nR_)qwQ|I8x%7goi8WlQ)8*1&(GI`)yz67-{!R)xNrupb?WP?zt=0~M8j E0kQ`-+yDRo diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTotem.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterTotem.class deleted file mode 100644 index 812e91062fa3b88beab4910dcbcf9b89acb8b8a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1318 zcmcIkTW=CU6#fP%yU;Cd(V|xCwYE?yV=oVCjWJ@HG(k+H_Q6ESuuO5wUg++C@u&D7 ze9)Jg_}~xl#l#0q{4vI}u(n{I8a11pbLO1$o!gw5&p$tY0#Or4ihh(0hD=MUP_ZNZ!1COF9a{{VIY@`$ zMZV%n#T_ch^u?~?f%GX+-isXb>VxfV(JFgR$LqSyjl#*yDWK_e7)mFFP1KYy+mA#i z>Sem-b$wHAT4A^6Mrs{uLTOL*gn@AwbV!Fa-BE*{$E>D?qJd@H&`>hKag$;853{YRBE&jN%Cr!mr{kMS_CPrGtuzZr!W=PTe)Ra%n zU|7gkjuIXSX&jD;M(X;FP0IbQuxZd|hMf$m-Y7hyK*3R<#bKK$(D69oeZ2p-?V{_h z(^J5ZrgtGuKaCFUCWzxi8PTz&4`A2@ef_fmJaHT)F+ zgAe+G#s`0ZKgxKftw19_5J`6DoHKL2?_B2W{`~d*2Y_Ad#xR0~5iG`V7x&b%6vKTy zP})Ns%Q{wcJYvwES*{g6XNaUT6^3Zet4oH7g5}C$+o?&vENV9GBnzG??27O$W%oCu z;jtAkOzw$L&)FgfB)OCerswdW`Q+(){=xI@x~y9vueF;^ z5~40z1mu>}viSg4P~EC-?Nkr8tJ|r80~I98Fy4@%+OJ4IuspY0MV>)7d&w}oOBY-j za)-(>eQ^}>K>Cy>@AP?j@nyLz8adBtd2P3z&0No&0-8>XVe`7McqtTS^NncrI~gl^ zZQqoyEY<79fl@E^VDm(Dgn<~w=%!Q)bYu*yV$HxhHgs$n;CO6c3)?z&7!Gc}=?n># z1h<9T;QO@`X@(5Nn~lQ|ALszX`gJamhVNJeujT3fQTen*{hUr0E^;n~zU4Nu`OI5} zQ5v6~&9HKXQ|50R&0LqO9a=W;je6|J_nbd8sejX)LuhcBU|7DwwHNThQ+<;!{qsF%#gCFqYoosbZ+}xs diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterVBO.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterVBO.class deleted file mode 100644 index 4aa5e2312610deef045baae4b327a76ba36d33a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1102 zcmb_bTW=CU6#fPl7FK#gt=DSRYN<6$T7A%98p9fsCWJ;I`zRT9N8GX(oSnr#<%7Ox z;)6fHf8>ktERYKEiP(pk@0>H|JC`{#KYxG!0pJOCEfjIBgzF{Tuy7MwCT^S9HgSic z_}q_teZ-Kj?KupF9ea{tt>s6uorZm>x}qPDrP_*J5jaBmnLaZb`n{hptiKdm*l{$L zN=xN5PZ%o4Q6!Zeh$NBZ(P_DH$dlpIXCL^-SOuQ+e9imma7Z9LF(MxK!%@H&LM6R} z-ofMEo5SAW&cXrZXfUh}q|VHaREZx)lOB#4Om|ue!`oUblA4FqjH|>u%@e7pNIss0 zW)@^ zG+@}Rwf+`7H8%dWWbgaM|8{|G6zDh6E2FQKr$yr-%_4~tGQz^cZ(v_Y$l(I*nKR4= zDkN8?4p_lDX$%{v(w>p)gc;e`V81>Q&U26ExW*axA}-CiO)4Zu9BaRttLDGL*#CSM s!OBj|CQ7C~iLyEMoJAoHE@PA8!YZAcgm;VOKRKrxX8-^I diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombie.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombie.class deleted file mode 100644 index 7b70c16b6062baeb32a5c346aa2904a8a76c0a5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1955 zcmcIkT~ixX7=BI&IU!wW*g~;{s4cCS6+CbzGpY7iNg(}UhH|#dG~ogpZAc_g)@J&lA>2}qrEi%NGOxyHV7<$r~3PUvSR0YGuqG^lGMr~iXWqscw zjaqaJ-KyxWDbFos)PG`n443ZdzMgmNW8wP3-F0gFCRr#2+ZJx#(mhWQs8TeXn&utN z-+iWi=D1c>R83#oZyX(w(5rf#Of|Dsx3n&A-rmgK%-mjSc5gP-^&<>J6$~5-U;e2G z*E1bEsDvu!Mwk%8r|F_Ce62<$8LocdYo2f^RqeRtS=(GIm-WNEQ>!}-ySkV;ADo(N z(nleCj9Q%`cV6@U9bY$&9_aO;s{v^n#4M4KE@a4Ue95p{Bqes7hHHp*Q&KX~)sK!w z`WsbCA+42gnQF)d3!6t02~P$Er;FTbb@1v@Ac^KHbo z>l_GA_E^D(s3=Gw$1oZUm8IK zNpEg1eRN4kGe$d&B$L|dQ?T!76TvvGF{$K3n4rB90`MxX(TQOS*J+i;Ig-*iI>>(e zhGeJhNQZ6orELnYwQPSy529qVr$(}BPZQB5dQVWws<9^c2?|*?o-~^1`yBI;<*b?r z4ku8jY2Ur`4Y+L?=g@hyNgmwhT}~n14o0|Zz-IH1uUbV0?N{6sUYw% zjPP+x@d>2(RcQPg7I+HFdA9pT+ninx;J}5Spguaqr5`XLnPnZ!sswq1bP>#8lB7Hj QVI5bIpkZ0Z`?0>i0KO#7bpQYW diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombieType.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataConverterZombieType.class deleted file mode 100644 index 8e281651076ec68c1c4c1f5a4565d31a48637498..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1618 zcmcIlTTc^F5dKbEdP-StMZ^mTD$1q63U~nl1&RoqUmu`b>2mfbCe#0QOu zZ)##(4LS0M26}h(??V z;A{XrLG+?8h<=0v7;qPZ0SviP4d9$BhXWXK$4Y%@nF zWzjIC714!lOLAO|Ce5sBXU4|Y)kmhKr({ZV)I>g$At6#CM{rfk=5)0xq8%TO50A$0 zjKoK}t3K?enqX*1OUM1XA}w1pjUuB(2A(Vx#&EwkYDh=T61Aiy9yqEkEh<^vC`VV9 zW@9mtj+oh;nKx1seFt-AU>ZG?(wofY7={iCuU~dVGILYp%H0hvn|UiK=QX$g9aY3D zIx@5-HiUv^glIEM4Po$TDUNXkmodRHsbC7U!@=ElDY%MhYFWv$qUpLwOH08FX36ii zWj>I$+e8Hs%+XXV@ijG+QItedS2*sDq1Uplvq#nt$~ZZR)C zG`_TIAx$O8NY?a!2Kz*c2Z!kGca3}#t)wd@2OP#xS}`2MaeBMpA(AfG*X-H;K(Z41 zxB~0@jcrFq8T$>sVkzm6Cmiw?;47f!9ah63e*t`|{XK=FyS4Q5m-RuCe?Bu?=%fIl zKmoPkP_W&XDxhu)b*@b*+9+Us_#;8RMQZ&B61692;7`%YpJAFmM})t?4gL}_{t9>b zYsC2*NdC4+p^I>>xQ!F&B!WP?Ovcr^aFXbpBCCR$A9Th&E&Mxb$nP}SJm|&|k|EL> P=-;D_GB=SN^Vj|YEaRCN diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspector.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspector.class deleted file mode 100644 index 8f814840081fb7808e80c9b886c12cb90c803300..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 417 zcmbtRyH3ME5S$IcCMJ>i0Xhn3SS3(^Xb?t7mQW%=dULUl$gzEA?#|}lDEI(A3UNuO zkSGw%&aU<`yR#pkZ|?xkF$%F4VxJHe$~H1{gs0_Dj;%DEG~A8T@mcyX z;pxqME|#&b8{Mk>DoIZM)I8q?6N?=tPJiVVdch zZFzC|!mrv?xy%d4i?%F1h+H(jkBhpg__t9<>qN4>P#ePNM?6fFk|wT%wbBv}*34W9 pwdC1iwNd5zzbga;LeGm1P@k}azV~|A-Piz;$H-UsPhb!Xz5q9ad}aUu diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorBlockEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorBlockEntity.class deleted file mode 100644 index f186876e1e446a9f533173884be90968ef91083e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6401 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorChunks.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorChunks.class deleted file mode 100644 index 883e0a34af2ff6eabdffd43cd369e59e60192b54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2596 zcmcIm&2!sS5dS@Y$x@WoO-R7d(9#yLoi>Wo5}G))!A@FC9ET*vfx?WDWyMi!%dR8` z0#^>)84gUR7cQKbfga4q00Rsh=)i>={|Ou@?2}CrX57KS!86wGzW4U)xBFJQd+&>{ z0bIf>5<-}iZ~~J-#3c-1ia#y}af#EXBuwLJ5tlK;xmf`T33GUc3s-`;%6H}kJS!k6 zAjJ@vGfcy|!r+ZW^9;UJy`(c7&lskjZPtpql~apVS{cgJHMN>oErZLQMW3@}*bKu9 zs-vb&yP<1N-AZjW%?ho`Y17oLR8_TYoy2@btJf5}a(U*a@_OB>mh_V0D8*)_LPRa8 z4M(>Wqt>V@+*+z`?&uaR*@bu^ezCANRhT;0#Z7`iFxs9OUW;T*-BD^3yJo4Ij$-Q; zSy6U6CX{S4ms88BdaY4!nx#ZK9X*@^gJc#RM=e(k+hK_Hq@AI&6eioIf103eTOcsp zAmR)YJ(<~yno6bB8VsUcZ(5q3*Dc~5)hg?b%MY$Qs#aN68*Y)P{sI;STw}N%>AwW= z1n&~h8yI<`mw$&X~#xNdW@MrWLy(;56o|BQr^9;d7(=i-F zw`D9LL;1>BMpnRzj8&}3SVxZG{9$@Sz>6~S*pTrOUZ!5oQF!}KZeWce_kZ*=Lx^Xp zR8_OAtQ5EDMlocM))T|vKW-93q!(y-A2THTj)gj2-cs!)eRpLux7(nqk47^4Nv}JW zVU`o==naMe>gm7xo?Lf1cIXQ%kjZu?SG$<&aUgWAw9hu)r0{8S(!E~l8<>nkIpa z0wK{|OSnAk3$uRjbYLV9_O}rH0B6Jgk-!~@oU|Z)gMpJ{pFwV6aO3R&`|!_SN$=PJ z8^^eh?lz9!*T(qA6rk5lY8r!-)R!0#zrwKiEl!EwAtruLUpGHsmFR}}BQ)_YOz|hY zCH{=}h~5%^aY1+$B4W6JM{x>%qA|ksF-m_J@8As1!UuD2_vYR%LDPYabLZ$B$NDxN zCtZ)rJwcooPZA%7?;b7)hzN+X-x2)-Vb1-AXb9wHyp1_#h;mh4FxI_bqwNEGp8Ysa pv2nEtQuI*GA0~Q+Vh+)lTo@9?OTSQ%`eP0Y0scuhhZp9vgAtV zK;DCYcnD^IfwTiNJOB^HuqT_QDJdo6@Q3fbtG(~r-P>L1k3WC?9l#QHbfht-V;ply zysIM*Gew$t4TU5YbSz>?M*{Du<^3c+P@3fwR`8*+Ehe$5;iiT)4YwG^rR|6fSK9KR z;&r>+Z86N%Tp`V_?F!51UrI9&{=V?d{X(;_*u1x3ZvFjaQydf-605dr%Qc2*CcDcJ zt9UKJaG^$4^?r9x_zk}2kY=LhS=`y>zOCe;GA6&W1BR(}E_u}rdcu;PKlG&RcvgqO zsJgE3D-I6=L8hPAEU#+@o#mBB=GUI@v_#96=3c+kp^dkAPm-^8x96A&v*NkrJE?-^ z(EaAZ%nQjV8qFSf!SF@qC3&cq8x7tjXM0}XZ56B4?CB0r#;k6SA%EIqsle;|me>_O z1FJHmB=_4whVs~se2mfC|GNe@kOozK|b9?V0wFg7}Z21_*jx_{Bd1QhD zLuphHhI8DqL=emrmgcGMN}1YGE_S4EyY1r3I_|kqHTUlYa=f9buc)a8L=4wYWdDal z43|zaq~1x0M}6+l06S(dxYJ_x0kH)~Y&T8-IU#z2-5fQ|Gd0oX)+hG~)*-oVu%(zl2s zM!Ln^&xrqq#QoU`?GVYwNF74|4$~w~oI8Z^6UJt*Oh3W-&y?l@X=Z<*W6_Xql0cx} z#ASUASM^)S>LnEPN=Tg>zz?a3h{Ag-bY~IQ@V0W4bTjlXig!XpR!DaKy9?Q|w2xf7G_G{!xn!Zq8r}SJW8R;aYIFC|7eZ1sR HFHQXg+ti1` diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntity.class deleted file mode 100644 index 2d3049e280dbf89a9e61dbf2e5e40ee1cb2ac887..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2676 zcmcIm-)|IE6#nk)kC~kgQWjcSq;`>CT?&jX6`@5aEuc%ctvy+wHWwGt11h zq){J8eDcW`AHXN&p-)D{q@oYL84{u<8clprqlx<9zd+D)ceb_&N@_9LoqO-O_k8Ev zbG~zCZr=XnQvh9Xbu{5g4F_}_M7M?>IUdsRlpGIhIHIE$M>X_m=ucn+j%hgFfD?FH z?mv@27AJKKASaiDI)*T;;#n2XsW`>JIK!5l>y=Di<<_Jy%WkP;J0&@GO_@1b39pAC ze#mz0;4nj^Ei=jx?RSfUVQtQK#L!G-TzGjtUM5L0=UTix$~{}I>%wR-Y5NT8kMV$K z9lt89!1azhfgQ{-7+J>=UVoYUzMw;+Im@k>{`7%^=gkYQS1yX89hl=Y)6+EYBCiI* zGwn*XY)Z6#*O?U_iTpxGp<`d+RA-@c+da(C4OBa{%y6zP=ZL_pknfhqCj!$K9-)}C zbqI5)FQ4b7ez#I}XPjbBHk(xkED5~T}bfU~l6!$X}J!d=! zc!};?v(w42ccpe1MJ!@fstgI=o$)L&Dm((u(mLQ?Nd&d^-wcs!YeoWYO%L*FEki2u zDoztC7_>uHxt?i#q=tCHmU(UYr)ck$cQlZ~Ch~-CLs$kzF-9JQ8Ky`YcpfiMQ0$_C zGkB4q>95##bFboh1wY_Uk$f<47B4aAN2Qc}bc#fqrNe%eUvLVdM2HV#Bg3B4j-**S zaMPaf-SVtRhep#Au9waRqC#{d6ialcUwKW%%LWQKXMkf|g=IisLIr_M!Zt94X%%Gy z6*vs}|AU1LjZ2Ie9-pE*U>JI^mMFJ(@SkD#O2~ePiy>(l8i+`X)xgl#b~mqATp-3I z_Xot>@I-#DO7v>J2WB=yHIg9Hi*D?=$Dz#KzEHCg=Vy4CN~3AHMi}rOiQ0OfhDT+3 zfqO)Qoy!60HN4E?A|!RhgumqIeYEO0vX2g|I{7(K;?`UkMSb}qetamO%~RP8uD+u# z;Zg_dU9Hd5i>;sx8*i6s36e>5+LUSWL zfJd=~Rt%3}D?Le>y^kmoB)ig{R2C5Fj;5l?XrsP>*d@Fv=TaDJPsSIZcE^)iiYAFm zXx_X|iM$Ifsm~*p)VkGqY)m%PHZLRAel-;fHPn=P15MXpB-f2uJw|7nPs!hVl#EQhvo{xLLm_{hq+QT&qen$Y?bmr!MQ60(7Bm{0*Y>ho(Agi9_Lz!&bb>K@ zkd{Vzi Dmnhh; diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntityPassengers.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorEntityPassengers.class deleted file mode 100644 index 6a52eb5533d95e85c0d5207b36e393641dd07767..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2312 zcmcImOLG%P5dKE5^{y9iOl)kx#4!XU8@$LSfD!m58`xMD538Jl17@@u#M;uXvO6|$ z&iNC$=8{vY0tY9RLoT`H2c#+~a>&ofA%UKiz@*BRh{!qYbkA%*zV7Mn-JkyY{s#aT zP&Ckui~$pwE{qx&!&$YQGcXQI$9ZHGH(_8B7ZmrQhKm|5X}HXgy6SqaoMwopGph`V zyk8LvhYGGIiktPa2ui$Mqm$l(@9^3x4_vix9VX;sH)I%E;F8;3*bt8NgGEoea{D$9 zL*Z3LK<`c4^F)xZsUzAxEI5AM3O6oKePTWFgIYyYTxpdzH#Ugy3U5deSZ=*hvy|Pu z?`?^Ij>5IJHiO}nrR3F`8%l=JwyYFLmf*&ndV^uSEtS_u8T8QK3>>j4 z0^%hPszOHmffdP}jb+}5u1Uic4dmoTy7RnebE-&UpPpw}*bi%zw3R4^>#i!YsF3!$ z@bPuN#Z4T3!=)M?IwQX z%}r{tSh7p^7?wNlhF!bVtlgB1-4tfiZ$Fi0JB^xd#A(i6hOhTwcDxZ^TUYri{QokN zOZ5Gc%?`JIE;Rx3`a0Pt5W`vc5~{{}p}ubByS}VT$OC{(A&w zn%)oK3E|aYHx}fu6&ABo~X`4igv0`^1}w{fPk$BkT{HrZ^7b zR4bqGy6G2ns7W#_#&Z@%xn`QGfe{jYlfR#8kMhWP|6TuLH~ z%QkX0t}s{~@iJtXcwBwPce&H$e%skr((~IJ4Dnl@@2T4i`TWuCV@@p839uZr1jAU> z^Tp<%*A%kGn_Y^Wtp+ad*17bwe;BmXjz{$4_qgH}KkN%v1+t<*EMISItu$70 zM@V#wfvXvGdBdHI9?T8k`lYG?|%IQ&?uH;XZ6ADR`&h8jwkBwNa@ooa_LDN!k#z-&BgXsrv|sVezCmi7*&QSJZ`MU=@ah;<7DNm1UD@NbBIh$5xJM;Pl?#@btpnQQTMJRN(B$&8hbudLg}j6E~^1?KBGd-wBu@jd06 zgbTv8$h?Rda}GIL3uZQ|VU=2%A>8wnp<62bsiuSrn2f3^A%m%?ni8hTGU)^;&)CPP ejakNiP}sml3L2QhSVU(KVV2s~Kg2AqTFGBm=2znY diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorItemList.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorItemList.class deleted file mode 100644 index 82f355d13303cfe5d3decab0d6607ba190c2a1af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1326 zcmcIk!EVz)5PfSqapI;ar34yip_Bk=64h-f6|@K;0!WcUC1?~OaR?h{Nlg+v*qb13 z9QX|`T)2V+0&(aE@FV;Jr^2jTkWj;+0xsT}x3llf?9BSh?&loSi%VYd!oF~%A5^61RozfBq$-{#f^wIK zp`fq_RmbnyVdu)#r}i^H=(a@5m3DK`>CnPkye~yyyS;wbR(xgO8;XFSu(8}&zSOwC z(pbrj6jG)7j#5!+j<^VuhtZudq}{zN%iF@~h!(@6eAN@u?oqi;z#mIH6amTF!+lMA z^JcBa+hxDk_Xl2Uqf%Ko+yMqgX{EiUl)O##M>GtJhh<5I{vdEfT?E8fVMt0Iw1tfP z@h!=n&RyP*+G4_Fu(qP`JFe>8?4Ry)QC(IF30zDe4%0+Fg#{EC>i?%x47GntOs#3F zHctIE7(da>h`Cooe&cVGU>M_$Bf>DZe0gb!;r1b?=-`mjT-7m0?>k2CoyJ(TgDed% zs5?nQEb{J=uhTkKD1HPhls-Uv7X^*cH?6kx1Y&v;mTn-UeJ02Z($L&B(xFh;`|lW_~< z5!}Wd852lINJ^NLFvSphpqsk;kinlw<`@ELt0)-yRoxVuwMs$QSza(`WI(kvZsfSF zd$>Iqa1V5cVem0`dB$|ALUS!!6?I{38@wTGhG@n#g`GCI;|QAhLe;E_;*^(`kCa!I zZ4^aOca=h|TqeVdyy^;D(JNI$@hH=lSr;}9Ir&sRHJ{&^%g>FU6>Eh-(pwrBUM5si zxJrdqq1k-jRUBaxl~Ql>D4T29EH9<4O4X{F#g$AZ*_i|7ORH2FW;%6?I9AQpM9xbN z%P>S-ZkL4H#J#&N*UB5b+Dxy6yA00~-DfPd;_a;O^(@2V^I&6;cbkiNs(Y0&a@JPO z9P&DkLPigjS*su<%tWDJRzfO@c`Qh{7sY)nGVJ}g!eEGbLKK6WC1tB{NJYx9dA{Ko zdjF|QhPAE(q!^|}c>@aL}Uunm@)Z44wYG&x+nkF1)JheDWt?>RFI_reO&dz~THYStI;U=Bg zVbGyKN4Ot8uXPAT2`OY5+2G_i_&(Ez554pbd4rKR=%epwYXbT)K#1WYF45a_K0*)y zvV&6t{+Rp~fsg3>f*_&ck?#mieWHKv z_z=!iM`=fAd;p)xae8hxG$1H4!GG@EbIv{AAAA1z>(}1_Ea58|!$`}BAsxnoj72O( z2=iVT?~D6`Fz(1$#)^cD3>jH*d?=2)0(~!nReU74)+FR4tV`Hn7}rhLaQBObscYPJ zi&m}N=Fd#sW|%FQx~sMX#pd6*s-xR`x~=Y|tLeq+!v(d=BPg5teuiPhHJbW{C+&!o zP}VRF_b!7!k=$ko5$ zr>$$QW%q47w30hFU?hTB@^qXZfl6%(9zxy>7T_t+TsJ7q9cSOO6<= zc2gCSbCyYt5z49de5)=@pP`Z*mJH7#hOZN6gsQYwsqjY5YPGG7SM zFoLU8&y`c^S;45F`HZ@Rf`TGS45|O#Cc=a*1)t(G1rJeHP{HRCwiSGV9R-i^CDqdZ zUAYX=e$KaQPpGFDN*Ak@YUo)19MkF58N=GZI@1iRg9>4|#5GNKoayw^Jk{lD;$%yl z)vbStCaJ@C?;Nj_!>yVjwy zkwo&OuVjzYx99dLYEJTqrrsPh5z_^|!L|L$ew#X3J_;yng{|CXb)!_tS9TbRgHMjW zbTP*@Z~imvR7U@D}~_V_1yj>a8P;{@diVswwC zUci@%`ClUN3xcUwsQV%PNF*O7=)6pfkfR95!x)ldxJEd|W5spcAc&FLn?1455kQb| z*_l}Q0FjkI>SqLhgS-NQ9LRFm!;+KjF&E^~slrJ|c8HK$w~5#P9Fw zo-gdC?WX96qoWY>-*PglAUjZcHyBPog diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorMobSpawnerMobs.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorMobSpawnerMobs.class deleted file mode 100644 index 12cb89367d2099c61fd6bf145bf3fbee68227555..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2702 zcmcImTUS#@6#j->PI5RXO+iZ)tCV6$kV6ne2vtfzO$otDN~^WTNpc7Wax>?ErO*8Z zee<<1zP4R0y4tn+1NtNSKiai=`6h{Cl`1Uk%F4{1J$v@-{q4({U;p~)7XV{e)6s=- z9o-lY;DU|`Tnv&ksbMOBxQ=POufvZ^YPcN0jN*KthFKj6%&B2Mh%2}nz%_L`8Ni1c z7Br+ZEDChFcFCHrxVF2!Sj{chSm=7 zPbLQsc7Q-ta;__jbg7{tCNO+Z6=GdLBn9-Qs*>%v0+D@bNl}&_d-CO)K+vgf*7Mei zN`jy(>qX0L&>hRJ%x^5pS|ey0mNZ-!xEelu9Aa^mGHqXs2+X|>ZNy-?;lmYXwm|QH zCBX2y+>!=*@HVR;vqu$Z_{hKwEE_nEw+QC`D}wIW1q~SkA7e#b@ri*?ag%{=6xj8u zYq8>F$uV#XpBcD~&xxpkJIETi3#lPzpa5F$Z2`}#HX+-KD9D;7^MkH47T{M@bJ zG+!j$U`Fr{)h;=D(59LzIVZT9=1T1yi9AAEB;QO$i&LK@YqsNfd#~OxTqj9q|zaQ`MMP_mwz*(9+gfM@D@G8?= zZYe542?dNqlyU@t)DS5T&XMkb=TDd#hQ;sb*E>N(M_M>ca#rF#A}V%)^eb%yQh|7^ vDe&|*A7U7796Qh5Hoh)TbMB)}U3?k7!yuSkqcgyh6G;2jyKw^fnVx?D^{eoS diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayer.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayer.class deleted file mode 100644 index 59c73f6e5030f264187dcf8787079aaa309d6e51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1996 zcmcIlTTc@~6#k|y-R@GM7QqV_6%h(WmV$~1B686*Ry5F%=nD?pp)9n!b$5#PZ}{dv z@KJqG%bYnUbG~z#@63Gq{ox~k%a}9JjEe@MxEMjd zfdM2U7>r=ZKoY|`E@4C&%?L&{q%@3a7-tAi+m0<~7=nqxRff>Kn-dJJ8QT#{<>I>V zvV6TjmUzascwv=$w$gWvA-QS$3~dWs^0ecZge6_?L4j9<#}G|Bj_~FS-1h|?TFqE) z(e$^kO+GQ7x?UkCa<(+r%iG%|c#fB(@Jzc{Dwqmw-gS0_M<#zQwU!!RTOL~*>pLXO z6oY2hA~QTrWE>&QBIRy*d_$VP@Ce1+*@ZBd=CWCypLdHTx9sGm(&@qa9H>iHvBWS^ zubb|>WzQ0;sxK_fpiA!Mg{IMYhdQklKZtw_&y@@mM4hr{&@CcPb-+`lU- z_cyYY5|OPVaR~0%Xem4Amm;W<#-Y8fU5*&Y%-rl)tid(=Lb} z+J_M6Z>MBis0p>KCrPSPs$_O}$sM%=e}gpPJbJ5c7sxSyKD3kUCGckYfKR}{S<(@U RP=^O_IjsKX0o<59{Rf)7EGqy2 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayerVehicle.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorPlayerVehicle.class deleted file mode 100644 index 29b4007aac95041bbef75846a41f79b7e9c04b39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1965 zcmcIlTTc^F5dKbEy6n0L7OjHd1*^6cSc_Mv7h*-zSc`$Ci5i2a+e2B~?$+G}?Td*< zAAI#m|AqRX#s`0ZKgu{~X%rKDXo_jNXJ+=y%r`UN+4JM)x9=*`m17tO&QnD-E*5 z3XaJeW$s#1?-(Qgy5%v9-rzpZ+g?kUzT@6)@V0QvV%;*Oqn@{I;pQ6L^91dESTLQY z;ngqAJu#j-ZlfxymTy!x>UCOpmA8E18dkH_Fl5l2V{ZzVOx|i{HFI`#d3JR+@$YO| z2F2RK!SE_u-R-esGhUonxZUR29_t?=Wb2-fj+R}bF+Sjw}PfCm}R(??7fSbtekh~ z8FApoZbW0yR)QjKT5{~;{~F)SW4_6C=onzwv+OujWWW>!XLaK5c^wyUk$Aai`PYxZ>k%v)2UqN z-fhudS}V0%G_82D@Tc$<-?i*oHlMmr6CxJoI`k%_J8bLv(A@61+=8fav%Q5}+pa_x zi=}+&9>bm98T}_NeN`5E#Y~;#rYSrxk-2z=j@;W_IKkTxcK6lUVb=Ln8OP}6&_GD( zA_*fTk0@z-Ni%3=wDwJYLFgk1Aq>(pDvj!M43VsFZNNV4Cyn6%;`Efx@6bm-U^*QO z4{4tfd5;q$en#JXWF!)cc5H*6ph$IW{44s?AIKpbB#BFB^#%5*FEOmX!cp}#((0Qa z={b5gj6*m`|Al*zv$^f*eCQL0EtZLZZ?o8>3zxAss{g)X^zqqVoQo!ra2hFI})9X8-^I diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorStructure.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorStructure.class deleted file mode 100644 index 44e0f969162127888eaf96d2519833fd340e9f97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2405 zcmcIm-BTM?6#w0PZFX6NMxjNERzwX@vV_*skVu)as1r_~7{Li~o)fRy~_wXdRph6MWcv&$)ZP&-vZmU;q5+X8`B1 zuHXqI6bv8{g{B~i8GlJCn8i7NIWOUrC@#pD!$k!t%tw*-nM)F0m9QY;GDGB&X_?*v zLohzE!4S&YWx+6@o0iBo>m}h7c&SDwG2J$JZG$_e&+i|Gyj!NrFucS)p0nJBFg)8? z_nfBTH62n?bCxBXY>m6FAi0~mVb?XcdNK8m_O9*J%A#y~TB%vB(#FfY;R#1G>y4V` z8_e3)ws7dkEhdY}bH(ek#o6)0J*62Wv+bYZ?YM3UPpeY~hQl{K%@qzA(zf@lX!%T` zz$;n1-msfiIi1T*98G~iu}YrDD>c*g7$&>Y)=8GaWLxy)sK9LtRF75=NrpsMW;#(* z!;E@^L3Zt?V~7pm5bbfNBD@yezwU9Py2=}^R!O)*vmhbEa4p_@7m{gzRs!$MFf1L1 zHLB=(D~)B-pS98dYJXyjZ*vtV5Mzi6%QHPwxGJ((QgIc_l%Y7wML=T6AFnfp{>RY6 z5bvfy{@^lXdX9xgT)oBJ6|u9nS=eb%n}_52LDF<c)D_Ku+gyA<Xf*Rm_cb`f!gzJ&uI9MPvS zh=6}b5cec;8tshs@Z=8&d`mGCBF+7cDXeDL#KEjab?Cw-7 zI4JKS^bwYPQrSazJ`}tV9tw|y_7J&;>5TG+X`uw)KFb3$`*^paMYt7=7|57?ST{O#T!J`7_MRpJSPLUH%d` z}UlgqPSKn3nMJ?+8D{$;Wu=<_S!+ zdqF=i^vxkXzme?lMh>?HIw6EHiK&*_SyBvOno{x|hiF<-I7!LIiN|1+<|c*3i2rw# Ig1$KNH+eRPy8r+H diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorTagged.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$DataInspectorTagged.class deleted file mode 100644 index 180915ed2fbbfaa2dd3c45aa8e19003619894f5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1491 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 QI+3G$mhn9C7*tr}KQFQ@P5=M^ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$WrappedDataFixer.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2$WrappedDataFixer.class deleted file mode 100644 index b58369ad6f5926d234d16655dbe8c029d327ff57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4486 zcmcIo>2nih82`N?$>!LWv(;D&f)&$J2`z}w)D|hAm9z+{;MuxOw(Zhf>~4U1izlEU zDkylM$mj=0N2VfFXB>C5a|{8hLA;xd`ipg)=Wdbj|06@TY&|8Os!DR)2<-|)XrQ^H#;(#W$DC7 zmMwnWOdira#RA=+D|lX@qGzO_@6rc!Q_rO+?{LXtSMgRdQ8x`YKAT}ia$43%#XCFe z=fDt{m&z6dRwr`09m~>mDN`G;W0r2xtFis#E{%0>?&;A6JM!5=zL-l>fy%UQ8K$1z zO~)JgoPg-03v6m4Fe}q5* zJuQj7+I}sTk%_vaf3Kdh<83!89!gTo859%3DydRx3w&LE4%bbwh2go#v^l{M0Sq1tnKf$hZ^8E&}b19Nt$kk4kvr_aFZ6gy) z7?v&1U2%BcKjXahMyoG_{C{FHsdQVM%~8P%v^7gWGBu=UHCCPItkuqPP^?%9l_Cm* zhDkcrWSb#-MC~*$PHAPUWjYFMlKr!smZ;)()Ty`wFRECM6)IlBAr&v<6$P)Vcnz-$ zY%iC`lpIs>1`Z1}UQgmEIHKYx-c+#_+h~$mMut+oR`C{&Nqvs1SdAtXZ{q~Jf>XTQ z@Kf;)-c|7)PSRT{PRW<|rCi-*t2)hJDn7tzDfSr^A4)lH41G7^RD6VwRXhxi89U1s zedaj8w4GV=*$rp0{=~qh;1hv6XF;0TXE_5+I;NAen&woec~Lnxg|t*kw>bH&;q13C zT0f;kuu(Bt0=9}nt$&OrGh8oLPx!=1y9w`7EoDfvy7hzf zgg56bm9(?W8@Dr(7OmGCox@%;hQGPYI|F^vJ!_?Xl<|Hf@YHqk{SSjcWYz@X$I?=M zrU|YdeqpgB0}B?&BF%3(FMoGnB~S00=>LNT1moTrP@glqz2=XAxXQgv| z2tn5KO1y%4!m4@3D`>!7T;)!(@Q@^{C07y_A@~sBS?^`|R*k_gFb2hgpAl&B)h_h4 zpTmZT?-#6X{2sxd5o+;Qc?rFY@Oq^o;*0oetCUMn30B&EM8%_*Q5o@H!u+m=@8Dh4 zSX<>C!vY_^B?qq~=L(108(56PRQ(8HN72kW-i~9~jN{mW6OQb=h!>@V%~%URpSAqB zy&H;@)YYdK>v0dYk+2Qe=xE!E7UD@$^&-xlmz=hv6>ZeBolw=q-$eZT2nj&^i5&{L zcks=FE&Q?hlngJwHKRe{>`SX>pT@_r6AqBM>n;z8G!|NK_saLXhIQu+mPNyOpc zkdqu7S`LS$lB&a@rX>&wl{XoKPs|bnVIjr#qWys*(O%eY4L!guIHCz+^;J@(h@16hv diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_13_R2_2.class deleted file mode 100644 index 0e5ec4fbb80ebd8c56acd1d4f3921cada978d299..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26822 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$1.class deleted file mode 100644 index d438928631b9e8804309cbe459b8642c602b51b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 294 zcmbu4v1$TA5QhIT#xs|I*QZHg?Q+2)X+$sySOmd5z_E8XnDf?Mv%8viv+x1(P{Fac zbB6gp28RD<{{9a~0At)IND|x;(l5936@N5_36F0&>Y1~9_K|%k@**D>%jeNr?=@lY zZY$$LV^^OXzg?XmB}^-~QK5Z#{ZYTpo0{t;s&d!10$uB^_^4*HHR`hUFeg0Btz|zm wIs^`c?3|{Iwkx$L*IY%yTp~Rvf(KKCLQ&A-(XdU{kS5uUyPNoL9{d15O5E6! z;zhj7W8Mt&9&g@1Uf%%BaNr~GF(QmJVdvcP2cb=_Bw=SVT@d_4$yR7fc$_Syu&m0Z zNHl-4%n0o!tPSIE7T<;J=4!R#S){63H8Q=J{%xHQ+^a?>;yNz{;i&TxZMB`Fcq?*x zvf(ZFF(xb%RWVbXoj-#V*Vb9ftGZ;rA3FX<6GlJ!;X+EGqmmmV z4B@cTWhIvxyIpTY;_|rsp8=0R=(!&Ny}nBueZb)^ypDnYRrfG-7`RQs0Q=tH6RFLB AnE(I) diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterArmorStand.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterArmorStand.class deleted file mode 100644 index 23243d52171e4782b9ca000bbd37eee1a6f9354a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1352 zcmcIkOHUI~6#i~IblN(+MgbKSRIDw&nE1 zChlF~Z*ZX-OkDT_{87d;ZGkqrA?jl8dCd9F``#ZvzkLU=gnMb6!b}pgNnB3j3a+Lx zhige>BH?-x*@)&;`7U4+r!s*r*0d!2eV z7*w;H7Q^#w*%P7RQemd#FG3>_k`gxBUEf7xYkhm0*GsysQ#asFpNc68V>jB#^c(qFhhoaI)8@Yf%Y&goMgfb zDcYGzC~dFKkja*h)9os01%6WvRCS0=h`knfXul`=opftn%{`+TQJ{6-cLb-!956bJ zL`DfIT)$02|Dyrj&9%Q96lM`U4sqF8gaRyOFbZGu7*cW1A7^5>0DV5h4 zCtm9sK*t1043n6mGXfWgMqp(eA3hQ7$G+*qDo5C}IM>6vlt_#)Sv{85;|EXliOyS{pH$Sclcnj&53pjd`} XU+g4!31^7vB&RWt({yS?3yIV(@SXuAix${wS|^yfNI(R3K477!p&w0TQnTUrOR-yrSToJe-%yu!0c<7ZhBSr%}0FQt+yR*QA(DVhrO7Cggru zYF?Mi8wp%V;A#SShWG``v4T;CXu4;PfseT*lc6z+eZK5Qqbhs;xIg^XCWW2hYyW40SiD>q$l!j+D(nKAAH;-*TO>jvPb6sKa5n zk#lf)dD)T; zKHkLdHthp9#i~%ziKiG++awMb8%>T_B?_ft8gC}>mWmn7QbM9bMFDTCn8Q2Nqpa;3 z%M(su1?xmLO<7j>lrlapDxz$vxQ2ICT*rIVx02;oZLv-^dDo*y@8g36Zm5{Y335nh zs9QZU-GT~%q6z~9fMU%&{^_EEW%0T#oU%S$ylEQL;Kw?})RiXI8Tt+~s|+nP{j-5* zIYjEobpAiMbtMh+E>%-iTfTAg){3y{mUiq6Qm=WW=Q>^HCE;H+*QXZ?>s4a=*iN%X zuAHrp`KV57(9VbbrozWia{SEAA5+Zn-*0@yiJ9vgx|WK zlz)XbP3w$N{ zz!3i&7x@>Me;R;(#8q-aKBhlHiHhBb@?(2T4^t`;`(L5yOjhJprH!;-1?)sgvU3n*)Hq(|HOOB0Nu;NVCD!2lRX5~kMvdnGmSxwptn8lPi>XwrnP7E94Ml5R( zRO_afso_oKMhT>$tdZg7cL>z=yGCkcgE3l0O&Oy}4ZAd~AczIzid1$AgTem%n3FQs zTMBV=XB_t#6tt^dbu7S@%s|2%H?um5*v%b_x8@5vCU7tL3GxKs04=SvUCXshe!35P zxLv=QQUS11cInuQcBOtlJ>9C~0X)cxD5IC+`|yy!lJfx$&%#PG14%QjV?Q3I)uN6A zc!Uf+6caig#X*5NRWhgJ3d|Q+y~$Pu7IpK{G$B1?6{AFYG^r}8uq2vQ0Y``OPR?+n zIb(M;X-0Eap}@+H5^aTc4Ug$KgvT{Jq2ozBrQvCTf&ZiM1RBqVu`xN!v-?+SPm{eiZHKE_Qyqr_mEBiYk?5UWTbU|6 zU%{GS6?C-BQf)d`R-ketUTzIl9c8!BrzF-mjzM5vSjF2`)l~uo)2(DnU||)ZDoN!f z;-^+QPu1-9s%yq;q**63ysIFnyOj;2`5&$=*7q*MVV|F2VER;Pe*WJX*kITO?>+{n zPOE$mQlq7H7MJC!e^*ERD`@7+i<$2ws^0m#;N#0?#+9qc#YhEd&7u}&FwFOr_C``J0VzB9TpTwT%iJdYYQQRj2t%Ecj1 z3EsZ8kgtTAPG4KduV_tMNNWt1AiMl+p+JSxyqz*EBU%Z;qj({rg=Gn~U4cj-q?b_F z86;C*LPJ-rw^I-6k=m0-QEU=NBDG%u;*xV?l6IlCxa9}b?GT^w!**G$d)k;W1toA>MD*yMrz zlH-QDfy+Et{4zuL;6r@Gv+$PFY-29ddro z4+9b(1^oCppy5;?SU!>xLcD-BqXSD($2(^OmXWJx4`0h)$)#w(VRYjfbn*vq3-;hz zuIcE(v$&3H0VHq`*P{zTY~uaZjTNZnp&rLd%1M5IAFC+m<>9`I)m-x-g12!4xfAtnk7;Qw)=`6Cm;#F8*3*j0*D2hHn@D^4-G(;F%^1zi8g3El<&fY* z7)~;!bydDpBsWmvSBy{6i@#E@fpHzGM+TdD$dO zyy$4$Jm9Y3>m6grJ2L7F48s-S`9}xBts9Qr zs-(amX>CFbFOo%Dc&bGuX)b^1sdeEJRrRzTIIHe%?eFtS-mz*YH! z0II*QMGQ;lxn%~K=BDJihFxKpPZodDZ5wF}elhh`b%qU#lLj|wz$bcxv}?|#o-;)J zL`RNG9q4m8%Tr=l_&xO}wNNZU$Cq35u3&;> Rob*8~V;oWH$TG5F`3GFBd=vlx diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBook.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterBook.class deleted file mode 100644 index b71ed5642aa4f2b36329a1161c71304303b9a209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3369 zcmb_fTWl0n82(PXduF=~y)12YDIy}mmR^P;AhcY&+zO>YTUtS-&hAdPL$@=_%(UD@ zyx;}Ay#g-~6M`{5s0pP3BPJS5Au16ghG2{aV}cJPCM04a`k&pU-KDjZ*oQrr|NQs= zJO7zIfBW>O0OsHwFQ%Z@gP;e?y;y;jUaZ1u59-8bjR$MRTrY-oUNm667&dsY(Thej z3EpNgY?9F8MFCoK@FX@%*y6=gc-n(!By9Df4bO@}l@Jnh*o%p16^bH4uO=ZXp+kbs zz!&O2P!rWK255#3Qj-JP8@sS!0! zf{NZ1k0}|t?6#`5syS_qv!`W{g^3!5+^FUVdW&Y+x@jb0sAG`ANmm%Q2I>vXQMxFY zu%)&;imh4Xq|%erTBS79HaDx$pxG5SyNyUq>HV=YFbd6AzfJ8?m6&Qol_tm1jVQUs z&CoV2>|~yNP@+qef%8O`J1FWxSqvNkd*zl9HP6yo#Z6RN@1nQnJEb zafb0tjvDS0Kp=Wx$4^d^9;oB%JOfLtr%Q;#y?H zlFT7P4)usT>*;}^SG9B~iEgj9y<3eDDvQ!3QrEY13&S|lI_P0-I#;R%+;=OHJ5+nE zwrhQR^R77Ewc=rP)(O)RnNCK#WLTC_wSiO@aoPHAvQ-qQ8#WCyM$Y^uM~?-~m}yZn z3*D8gJ6RxydALKhmQi(FWF|=am}W$sj{gv#H>i0mLEfZC4RP5E>@d zF*maK{~?yX2Op*%!z1*8m`y)=N@+KZRtnAZ)WALS6xc_!$iibZazW&uU^=bkBm-t( zChZu?P)?%|uB2HAy9#jp1Dexi&!)+`24pJ|G9;U|3T}8v-4tI|nJ>E+u3oqgvk7HB z-V146xzCfI(~F$LjESYE7v6^Kd9ET?MK8v^i)$4{#4lI7SvB{K_q$2<2;TF%`;dDC z$NX;6mzO{F7z+JvahUIlBnU@QkviLR_u1Z~C^&A1=g8$>popKt6mqMS_hT+U zk45|fmh!LA$iK!x{tXWCZ*iPo!u$L?oa8^CkAIKT{0h$Ut2oDhLO=fz7x*u@$gklt z{|#68uei#u<7fUmZtxrUi~qs$c|R-WH`!!5RM)JRy!{>C!WEn#uV_(`=A xmav9_!RP%GCAY|Q7MT>#TSjICvR#Drb_C!hw6|j$7yn<{@e=LZP>9!&^Dp2kwygjF diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterCookedFish.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterCookedFish.class deleted file mode 100644 index 86fcb22f2cdf4222114e19ad97ee99557f4ff6dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1576 zcmcIk>rN9v6#k}^Zd4f?pZ=x z|GD#293&ZhD~4&f4;XqP(JX^EWfcU&K$@&JYL&dOGdy1=O*n1oyqx8>A=fRX*WEE3 zhLI=SeDf(&Eyd_S&+`1yL|uEnh2@ zNbmx$5?nJX)w0&*(aALrKR?l>?hsKN{YBx*-K?-3!!jH3tT8Bh^H>b8BELz@#^X$e z7gJWHYSqj_GI}<1BGfBYhWJ@wp)Hr|rFC9y<SLiOoKkXxmrYpB}hkl*5?oOdD-{B73rp@ilL6s^s z97%Uhyye=4Sxl})Uor%!N1JPgsZ)%iCvjAU(+ugR`ovz1m+4Y<88j1=Y_K^Uw&_!x zoFtPEz=OZ5BF5;w3W4q;{g-7E(wpX`pBj`j=V+#pWF&iMj=YJ z4KR#Lw33cSX_VkNNeT82v9E7P9>;o*VZCka6|(d$>0x1mKg#`JF7FarVLA8D4H4FN%Kse zJnbo4PQR2n%hH`>p1ZCv@1``{ zRNalS@lExC?c}q1*6`F!abtr7&+-D{Rl_Xg)dO3)D~XlF$ja^Ez60)>lO`Bia=Ise zFYAtL*w$V~a}2UpCdP0-oU(LJH7PaC;j5nN>JCv>x5}F*)P_p_x z!WlwV#`AbCZ@3;qv@UdtVu`z7GYbqubwR597@C(nu5HZoLZu&}CA;Wo`ivnu)_tH> z)e;V^^DVAGK{K^^mRs4HD#}n5Ttq^_FfPd$Q80>51($I}!5GFF+NK=SuI;dls|-R$sOWQOj$qnq{?`HmgJL%aZ! zf7eX(B1kU~LlZqme)?$8$Z8=?CCNxOM8AN2CdG$VS|#C>9;1zPr5u1GI7$|gL?^8R zJV;W2{cW2cNz_7jYM}lq^fzG@FxiQ<``Usf_}^oY)W#A5^YIcI8g|hW_m?0w zz59TUc%Y&MDW(KD*4|hFO_5p!$-78YK?7A#PrRYJk+i=N!Q|K{L4PmheyS0qr)ZL% zp+kBOReFI@=_PJRuP`gU#zW~1o=9)^@`@sW4tlpw;3Q=|OP8^%Q9hMih1QKzlx+{4 fAi+2Klj3|hO_mR52o1E87DSX}h&mI+kQDq4mTQ_| diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEntity.class deleted file mode 100644 index 235c934e500dbcdef0361eb73ed0b6e5a986ef58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5985 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEquipment.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterEquipment.class deleted file mode 100644 index c2c5f8fa385b4e4c4d617bf07229cf7a237a84e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2356 zcmcIl%}*Ow5dXbr<27dah{H#KG+*Sy#x`3hX+xZng29BuKmrCzOM=$+0vqgIXLq53 zbB{gs)=0fIQV%_(s$`TR^$%$Of?j*?HHS8;I?rB=jVjeuTUmZ@X5RbF{N~M!{o^0s z{{UbV8v*oU#E*9ZXu)Uz5^nnOu29~Sa7*YTVi^<5Z3%I4LY5ZX5tjG;8296@&_D2F z!jDM_32`tLKqsdCNJ_XTVOGL@2Hzds(4BDxPbj>?;7yo0jiEiI8`}JCA){GoHIpYx zFlA=d{EBMnLU)Z`XIr-!x~Eh}O_;`>W;vQQ{cKk+7Bs_QkY^1;vl4mLwl%u9n#!65 z#ooC!_DuQ2wDLJEr#nh!cV~w-HK!H{t>}efUa50vZwzk?k8UiET&*)#yo2pcjnY$xlYtF zbiQQnT3Icri(>ZIJ!JKLhn}i?s*HY|XK1cIuZ$GtWXxlMtoKwSH|uBxTgF2?VhAp^88Un0&7(FbfH z6676$5kb8VNQD-S-^fBS>q9@XyDho)Vf%2&~4A&_X6z$aFDQLhCBw+Pq&O z840$#!1xK!dkl;=RV80ll3Xbg>?pe;E+w3a1cMzE&G!YqBhgRX<|DzguJ4|Sc4=lw>a;Mm*AQjbgQho_kf8jI k`){yZ7IME)FL4SXdT%Ll2+W{gWVyJ2?|zlDGB zL0@8(W%&Vqlx0sYkQBa9>cdV?_w?yL-P5x_e|`G_U=3SwsF;i5W)!#LxQ+QZ7O)t_ zl2j5=B&A%IOG?2V1!)C3LuAvmO@E6am`D~GLOG`_7)JA^E%q9jc)#THVqI;(3Re!_3;@{_6aIxtAu(Fj5h|JSz&~c1FF?UL6)anfBi^7Hv zd~Q^q^Ln?R@dKyf8se!bJ3cc|?r9g&N4&{Zj9`=@+G_$sz$`1ss94241#2qq;{ikX z2{qYO@eu0_!)>L9P_cnWDzeyA@R*_SKdy#hOp?_tZddddr6XbZ4F7ZpsH%Z3F|1tV zq8VZ|ItRXM+7*VyME;C!$4HZK&NNU}4;vB34Q|P|&>y5zb2j;wAx??59mf*#VGKC+ zGLcivJ7crdAE@hdo{W665m(flCQZyA!;-_+-(4=|Fhsu=>NWjmg7neskv2v-hr vlsD~klbw*=bQByjxJC)DOOgo8hUxr9o9HYiNNS`HVFi~Fr{1jKZY1^_I4W-} diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHanging.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHanging.class deleted file mode 100644 index cbbc794e0891879c1a7cd40d93bcbce01de15b9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2209 zcmcIlT~ixX7=BKZoL$l_#T8K0T0d$egt86N+LnqmP$V`$g%n$=g~MhOmh4B^Z0ImL z{sM2D@ut1d%T8yUsoq3KM}L4nNu7@GNft^hmT}aXP2P|5em?Jec7J{J<1YZlu$9CM zcw5E!Brf2hit!{a;T;tdD&CcbCE-I>|FA zX1gGU+k*wq3JsT9G6PW#jk*<3sm69YaMqa56^o)W<-0Y%;g!bI|ID1>nB_Ixk{wuP z*ec-kApx$C`Sh+ibr3V%8pFsTUVo{Qff1;BVN+}i!y(L#r7$4eDPFwn2*RJOFeD_K zr4pAyVOHlvtu;9XA1b)PkX-T`foaXya>6fm;JXL=h)kg2C7fV5VwV)$)UbkE4C*yu zdm&|{Xc|7k#|&Nh&~j%2;Zit0BTPEfa2u<1ve&PMH3-VCVI3wFSfu16lwfHnBc-8& zjYv(IY@{M#MZ=~%uELS4MTr*uP)NWvxR7I~6dHV_6cCzA|HHB|^gKp;VSSV4&G4UY zH4Um`3LP2S^JU09eVaSBi(&Zb)}32LgQDBCnRMD)ht%h)D9sBlsv=JIl z(;8|UqJGudStu8GYP1{u`^}=Y%}YClvgdX}GUxbMGO3?23 zpbR3o`~bdL4--w@gFdTXC+Y|r&g47Od_Cx}xL;OC5f zq>0#^9v^NZF`;uw&c#pMgW4Cri?1`f(qlHE-ouv}y{pCEg+pu;$scg^Vj`n!^fYm7 zAkjqkS`)`JdJjF3=9#ue&**xjdA6;g0KGCpHlz1NVN=A?Ly;33Uo_EwAH5mFZjKIINR=PthD zH9X*3c*sNi#P75Kn}vc&dWohngajTyk2nG<0#R}q3=@nBnlynCg1s9LX^>~AmVVqv zmbf@ZskVN^AK|2ew;1~!pZ$Rz1!KSAD0!T1jq4m3grc-+TSGe)Ic3KmQ8gIKGTy z08>pkifMrham?UiGoHY#fT6R0WZez zatyD;@TvyQ($G3}&04mMa_G2*X@^4^noK9>Sz$S_HFVUU4p*11<>d@B3>+^vG(ru1 z*zufjL_M2q@Sg3>y+c!7s`dS9n4v2mpgLG&sgrf6*y{L+iVQ;PDw-iSu3=X zzPD@#p&d-vmK)|ZBqlx24w9}_D%lj8o67hFqqKBt@Vc?$2X5BRI-!v+FD;Q+S*u7@ z!zmP9qt04sVPIk4_`>Y5!*$!$OX&ZmoE@r@c{?aMzE_E3QbR0Lbw|V1t|`wBjRFJ8 z1lD3`l}7|#?@gSQSmb|<7iS7Z4gL43-eQJUW@*|g z)^aL_Gj6RUanmmc8GFo81=w8||LwH&s}@M$Bu*vp5RPkzIN2CpPv8x_8N*u%yp4A> zL{+}V5_lKyCGb8zNZ>I9vhWMGF;0N^3%QC=GE2ODW*SbM} z;z?`SHj7Ty4w&v_-pMT4D*Z`+MXdwdE~=B}a~>tm23AfLM^sh?i)>Ssbwb*rQ0RoK z6Mj(QDmtFGO6sO@$MQ(Uc-acFm@>bHjFhN;h0|aug(9 z_6uo;g8HnLPCLq=nWtCu&ditHCFNb*bX+#WqElkS3UkSJ?NIp{t=$nbJ%43d-K?*N z8a1z%9cDw!JFaWxl$DlscHDRE0<|wWVTK0dqLBbr5Oj?7DM0b>F$gJL@JMtH5_2 zT8_sAZ{2948uC#0WzHdX(|LP!W^rz{$ZpuSQLHuyCzYI_KVz=1dc4k5O{SYqTo3Gm zzf2={72x<3rQ0^{cF&j^vHMiDbH1N*ZG&vV_eflq6;eZ-fy6y~Wx^`uxzfbOoH5)PBxjInq|u%qpnY2r zd4#B|O}zs{v{aMl2_o5wnM)lk!p}FW~xzcGE-66YNmAAW~O3t zvzZc7nyEHjwi9D=3sK0e#3s3o7?<0L&2k4ZA$Jm6>}=w-Ne1JhqzDn68FnK;sJSt rcu@A6Kf?GP5!DphhRPmfq8{g71m`hAD#;ziOL!D<_S;K%O>g=al|E!3 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHorse.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterHorse.class deleted file mode 100644 index 3b5b9119d800771f66066e76be029e1c0ff7c63b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1602 zcmb_cTTc@~6#k|you!n5Rq(EO!*X3wM39S0@j@&ZZ9}4ol4(2ErQ6-IyT$NRd@=FC zOO!;628|{fU;RnM7|(1g(%=h`O=iwFXU=!#oH=Lb$FI*{0Sw|s1g+@Qa9Tqmf-ZDN z(1TtLeQMFKL09sOh5-#{HJsBhs1)ZpE^rKUj4*`949oB)7=nqeIfhWu&P#@tlwrx) zN+~OyjL4d#iKpzGFz1A0sC7*l@*Wv3?M(?!ByDR+I-YcH*p5qt=(J@?Cus`Tm1L7n zPjYiUT#mUKQhPv~EbvbWbMgM|W5>dplo1y8d zlqg=%`j_VA!cf5`attunk6jnjMm0gfIk6}mKg`v6bDj9mW(-jPj z)MshWF{}bZXCn1C+^Uk=W{avWt3TYZT&xI_euuWrPO3SNcHN_z&_UA{HK1YndKpTHWukIUM<||0@x46kyG0Wd$j(@;i z{t<$ILY{wt$-lzk-~IeLd_VVbl&&~HUcFkT3LT@E8BUNk2L2PnEJ7b&M*~@&By9kv Vu%Bd{Pz#2z4-qQR5H5xre*@zhlZ^lX diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterLang.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterLang.class deleted file mode 100644 index 220c399c7fb3a8a3aa250d9186762eac093a4191..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1393 zcmb_c-%k@k5dM}Py=yssRly&Kpdz$@J&LFxh6hVbh$l7B@Zf`FdtKn@^{(DsA^a)+ z4?d_5HSvMO2Tk;kGR|HLw1F2Q$=%M*?0hrd&d%7 z`*@JV1RhFtQbk%tM#VHk{Dtk>;R-`6o!Meg@?Kdm^qaOT*6Y=h@Qb|UkR@e$7I(I| zZ%e&pRKh(wU>IEGAthBQx;`A zG)nbKg#<728UYQvT62t!SiyE~JGZdCF+b5^mMNAQ`gTPq?OVbRY|oAMu*RTTO)3oU z)21szqe`2xe7+MJf$)i>anOvKGuB@gi+nflRcl_|EiY#-=S~T&YK&`Y1)>kN!yBblBy^4 zOz)6x2M-8*lDHjqVd6w^#&+rgw&%&p8@=*>=Z|q{^qepx>1~P8PYp;~FU<^+jAZxp zH?S`>=|UfkacR_!(NA;fN)8ynHIfY1F+`&TXGzL6WiU4PiDWzWM;lf-#SY^}3tNUl z{=nEws%t=NAodYMG^MWri#6 zh#50$T6NV`*R)2==&Gx(x@KL&%C4_&)$QrJ!28~}-+S+$IlrlR>g1~1&;I+tM=Z-4 z%5ICm1UMdHNd%&>)cxaxVLZfK6c0fHA&F3nP=`>DkV067(14Ie$RK19atL{Z

3Y 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMinecart.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMinecart.class deleted file mode 100644 index 8e4f1bac7d36df22aa9ad89877e812341444f74b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2029 zcmcIl-BTM?6#v~Mn_a>JVeJRD#bQNC0NGNDZ3WR1M9@H$jc8geUN+ZsVY8d=ZeZ$v z;)@SH`(SkjZD-o?x#Nrv>gbHl_;>iAlMcKHi8r#GiBZmwS#?Gm@Ip&0tBB9dntA_yJdi(^?~Q0*ophMT#fCnB>Z zkp=vN$P7h5V9nj8=V^0op;Y44f?uoq4X-krKbkt#gTgZoCzuW#`Up$XuGJZ)j_SA1 zinzVA%Ik5$sYw{LIooZOEMxhNz!po6EYRt$>>MO*N;Zj(VLU;m?VK?roQjHd9TrMD z-U3xV+df=(Dxz8QROwD#=y)6N=y)8bRFrjG$C!>Ac$W;~_Uq^;9q-|$j!nGJ(AV}> zxFterg@N{dsS$YGCcM3ENolRrac6SKQuf-=R>M&k_@HQO6R>T#{@R~3+!0u)h*A5 zvC6rW4n)o0CFlPLh7``q+E;zQ>I#$Cn(q;DU8+_*94SuS6MI*KfZvhBl3_e|qvNV} z+)YtDQx9}$!p#4>&cX;y`;%Z8qVJS^OGHo8k0OCHND-yyNs_a~nM4^;W&BI9yRpg$ zt!XJ#zQL2k>rDlm!_%~*l4FckY5XivX`IY%e@Y~Q5n7w3-*%WL4@`5&w@mLN86#OV z5)(#pAE|vPAK{XbUY#)1eQ5K;ALGpM=jgeI48teL5<7eky$O5`oph3u`{;{R`zJn= z5aPSfK_l4Tpg@pF+r$@h)z;4N%FJU z!Ya9`I6LP_sw43`W>ieG--y?6;UIs@aTLJ$toi_YIccP=a>^L6%8HS-%4uWJDyxQJ xl{MortDH?6$E>e#{0sERRI`qJJt7>>kt{(!^HHJ(aVM~fr;s6ht9Ucr^Cw4r4J-fv diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMobSpawner.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterMobSpawner.class deleted file mode 100644 index 85b147b39bb0ad2eb5ed274f2fb175e4717f3eef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2430 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 Xj)=(M1WC0|Bah=qk)FpN-97&UJ}>eD diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterRiding.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterRiding.class deleted file mode 100644 index 39e7cef82c1a75ae19713aaf8e05da07d4132665..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1944 zcmb_c+inv_82%`} znwDHxZI-1|66FTnB#U-MG?s;9s_*bJ>fJM4hHaOGCknQ;CLK>Yi)PidY7F|EWl5*d z5UwjpsZ^}kO~b99Is3qPXgiInteT!tUai+@6IIb7Q^Rbw8b+5lcO|!yn_gKweyHm@ z0Le2XYSL4ZW$C!4ZTWG`F=&;54#S;P(UP9gq<|`pxa%3Nbcm?27WmB>3$vw?s1@vH z%U-pr`H9}tDOXn6^F)oJ^Bv?Erh0V|sWe**152K$)aOMj%MaKnP)G>>KhD!{KKfd=EhEymAf|mpq52G(R_Sn?^=ds|-6f zii3dizSNZzS$U&0H2!vf%nDa-W}f9h=dO47-oovGXOd$7Oh(1&fba&^gn!*)9BfdY15Cw(#O!fslX z@f7XKI690cuW8?C`*eeCv|~Gl@zC}$BJ>0HWRiVD@irpAVtYE%Msz-%$+od2Tm1dg z$IKhji1>_l6DROz=;zNd%wJ%Xzr-&73gi3_A88-y4I_r1u!ne%-w;!s_R^nG5{N0u z#%QJa4SCebE=rQof530Ohqf?DBw{zS$*q%Z#BZ*rB&pQ+YsC1UNbtWf!r%D7>A<`L zH;My39Jvh1#3=6vamWXv*CPbJK~z)%1}On;^w0a7o>dVCc}yrVe+!Mj!vJr0q9l_J g*kA~zbt3P>5#Pg6f(KQpk4is{5yZ)A8fW;{&v*yt6#xJL diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSaddle.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSaddle.class deleted file mode 100644 index dcad57ecf494ad75436728700a3fd36b9951c59f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1806 zcmb_d?M@Rx6g@*>cUf1(_4`}#3ut96qJk)D3reLFr4^$;B-3^*E8X3?JH_xQ`V9Wi zAJ#+@AHY{KG2Uq_(tuH-X*zf2_MAKC-nldV`u)=v0Hatmu^&SQ;sz2XOk6ZE49CDF zwMZHmQTDQqQDq5tMcJzct|>caU|iYjYM4;N4IPs@Zt1wqpxtnNS57j-1_l=yy3;{f zFzn8{zR1_!ZGr?}+lz+V-i6k(p1%Zg!Td|!m= zDvu&TphC73cuur3HvZCi6@=BYD7(@r)>l@@@G`Fv)p5OA)#->9EhU$dqe}}TXFJ@j zO(qz2RfJT(EQ&C41HYL^hCwg2CYAbHi$)ySfUP%XD zEvWnDiNWo`saAebN?xJtngNmw!`lrJD|t1Boq5SiD|5WouCAF6>S0OTbyYQwcBH>v zmEjkBm0LK7Lkv5ned)@znIMda(B+mbq>$DzWnmh38O&DEGE#UJ?qP-wzvZ!z!F`6r zcIw2?w_eigQS-4=g;yf`vQ^Ivz1B{QrI+QK}wJ zmHQQEzW73vB*TC0J36I~gJ9^T2F%OQ^(zeL2eQBRZ#k)-Hn}=v{^V-nWt~^)qU_%o zq?N?P;8VI!%RHJDYxBUGeGm0FX(**&Eoh6=nKgjD#g6y_BsMi_?TR@?ru1yei{e{)BhIO@Mpc)=B12jHRaUq;3&Ic%HlsvGz;&!Zo?gn~ZBOSN3KC=P+4aVZO z(LnEOIG1xA*pHj=z43QSPBVpm7?i>c`n3#( zv{{U3S&VCQxUJH TtWC3hxQXNRcXfd59j*5VQjXV- diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterShulker.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterShulker.class deleted file mode 100644 index 9239eeeb8cad68b628d8a0b3ec9e744528d7f819..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1337 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSignText.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSignText.class deleted file mode 100644 index 33eb0d1143d8f6d6d89a6e074ff9b66a15e61447..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3121 zcmcImTW=Fb6#gc0vL1Ia!8AY;T5bX2BxXrSTZn0Zn42L4ibD#4Camqj*<`(IcGn4) z0=*!izVJkaKvn5mALv7Ar35t+s#K&({ZFlWX6*!gd;c_!Z92VA{oMFoCxA%5CcJ+3SuyX(>NnnKa#^)1*s5LV~Eqf za|(t-_!#GdxS(Jpgp0T&hfm}%D%FlDxEw+=`W5IQY(&4Dq~(xNAQW6tkYi{(tb2OG zwx)#R2`6RbtRZpDV^EWpC7gt*yRL8$AW(XwgtYBC@U|3?Xm`@95NKc!@i452o-5k~(L(a?0fH!WCfni^{JGpn?Rc+dK z%&f>7o|Z07P7=|xdV$bsM!sNbRe;^GuCcD3v9sN+RqXk55V&wocyeu6IIdw^KFB14 zk|~{;VYF?)5}uYPv>8Xg;%TmM$Q#;JNpqJr*grI+=Mr|lU>B`yJi4;&WH6I2Fzi~X z*s7GLXC_bSg|ed(E5tc4p-<_WsarWMpuBTyf-DMie~C zLj~95{u>fC4cl>3#izJME_+>87FmDMpo(y)OyugDu98-A@on5u@fki>@CC!r|6zrp z;Z;VKQi$P=Rz1V2s(h=mSgHYr&gCOpUF-~;+Q+=;j<&^h5?#!qsu5RGcUrC-xBU(2MWJ~OU6hp0FMZOLeY=BBW6-uOQVQ1S0t-mFaO z!-CqMp_|4HnQnt^OZWW6hpyoGmqvV~(lh0wGaOhR!Q#4Vm7r1;kixGsj#m13-aG%& zY!}<1n}QUr6dhd#uX4IBzq}6dFtp- zy`DHx`qGF}mqcCrEZ8&ps6ji8^^(aCqJzHG(gt)QMl;G=Uq}kaXeNbg8^jMpDn%0& zqO}X6yU|4gQuG#TX+O{zsp*K+&LA*@x<}a5-Vv#vg+e4)BD_RGL^^(yrhItK1Q7ff z!u&WIc@i7>32fsh(ar~byX#82%XY~My0M2W_xKuEJ1x^KR)WHwA|Tb_Wk)CB7-YSH z$XhXj^BCX6o^#l!bSbZTji-z97_t1aB znph+fc#gHbfu_Lk2+P&T+vVlD-a4O2w${n*74!8K^Oj1Ll^Qxan*zTg@*Epx(DaNP zbe=BUX*AL$au@fA-p2zxBwBLaDAtqf&Z3^D!1*~e@nM|g^mOGT$nuLY_$7G!GN$<` zuJbf*^DOT29PV*}ulNM+a}y7^jfXssN8G`;+{IHqjTwFezww*C`+NK(d%58Lmw4ZI zKlvCRU@v*U9xt$uzG}fShhD@f1~NFCp#F(&1^X3zxIt~9*K!{_wJ@v+A&3JDx!X%Z z^4C0v<_oiEiA3hGkv`s;!Miiq^fT7Tgl2xmgvk{67OdrcbmT1r;UKNm;1F7gZY52d Yk;OL1x4HZUiI>HAJ*NkJ1lPg;1_1jx9{>OV diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSkeleton.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSkeleton.class deleted file mode 100644 index 859b5c2505ff39daff05b10f0ebc21bbbcbf06be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1539 zcmcIkOHUI~6#i~sw=Kh~il~61AW$A13#hzArD#G@Fp;JvE+CibwG5p{nVHt`Q{1t0 z<3cwjG0`93PcqSXrVpUO4N(^}=bkg?JCE<2x!-?%`37Jf&*SLCSQO)NOduJ>WE@kN zj$+2wQ&FhCydOo{m$Mx691l1iGDKE%OZQe8f)mL+LnvbxBtv&rx8zpE+>=gD>=|T9 zWNl3tdEw~3-ZX~1ecff~TNj?l*j80Ko^-ZL(vY5QF(@0BC7p~RTvw7?KC9WL>XsH3 z57l?JV-#dT_td>gsYF5)M47;`Y`W>8U0)r8(lQr@GRiV%2IRa$4P5%jHBdW1D5WVilH?mvd)eIz5y! zsF`Jk)TQCXP9l3CszNn{RaCbo;(5jOospx^p5yOzJn`tRvHetihj}pmS*p9mkU*E@z7)hoey5j}h#{rmufyo7OXV49nByOy!U z-Fi)vl(!!v7{pMWjFo0}R10q5Hq}R0F@|x6`ngLPIuZOyfiS|99|)6il#Bt~!!?o# RIw_b#AL7LB93DktzX3v}hnfHY diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSpawnEgg.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterSpawnEgg.class deleted file mode 100644 index b24b8aa19afead21a35faf7c8c7e097064b636f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3852 zcmb`JX?PSx8pr>Yq%t+hgoJ{C918BTLI^Mfkt@hCAqiO$l4VAMAcUTo&PO@lBJjSz2LeY0jtLwW_)y>@fsX|~5%^T#Gl92EB-C%4o!nWb0!cpI|oK!tS>3qwv`~?iflWJCyY=fIL87f;X$6TJz#7!?| z#BExUt!~1wR~nwB<^zi*e%d0-)k_TDXmFiPrstbpG;8!ajj0qvsKs$iufaBQIg`Xz zwkF(6IM*|0?#6Jh>)A;&Y5C!JzNd#^B#kU7hpkN34xeW)*Hzb5H?wQSj0xv04{k#- z3`v>3dbiT_a+d4pSXvkYiGoWE>n622rXS8wPzlfI_QN^TBWJ^#3YP1_%OkOvk!o-= zSvT(_>uWAgoPkkz@>1!obmG2mq$qH0xsGAl<=Vc$#0;ugF70~$blNsbu_iKEhKi_f zBzoG6tgcJ|zhV&c6ZSxD%c5@HOPEcTs^pmS(s(Aj(^PYWa3fYztDMQyyqv0L7j+Or zk(DIFA^aM@3E?DuOM6pjA^Z-%X9zYrzUB8(7RkRQM#e~)A^ZV<4B=1sa|oSS6~Za} zC4|4?Zz230|6r)PupO!WT6{CZz*lv&dvP)vOMC7>GX+~sBbQ$0xITr}VOX@CLwoVX z9*NLW)Ny;`hHcZZ$@0v?up*kFrL*&@0fSD`^s=Vmk#tpKpV{8ss8*s@$}wmuRFLX$ zecer!14^5-5!d%s3WLhcCeO&wxV+Qy)1=#zS9=FLJS$@+V-9&)-b8zolTpJ-(jie^ zP}}$9R=9~C(=X(Uq+(V!YbFQ6sEB6Ggzp*lnRz;I_n2OUtea$W$P&*;xz5>$$`*SW z*Q4sIJxU_3K|)n+s?iP4UtuN9!tt#bTxv+0ITEQHoHyk?$4IC+23KOsW38JgR#jRG*T9|Y&y=}RxVA75!={8 z27;~B&jZHFwPGQ4q+6(1#LdyEEsm&+aau}{GIcSzm9cy>Ae!@rmn8QnhG?M*Bu?%q zC({%Y%^Fne1sc*8Rg~m-bYtF9b?9{MZk5t}jvCm_6vR}AwkdO^?ORM+^>M{Y%eLvH zc+IY@`kwq$hiIwm<;a236-GR6k(d}1qt?_8Hh6tG->?JtCqs&wi(_U>3;mI^=O65F;Y?}E9rF;BdN z(8VFEZ+bClF~lz=|6fxcF>>br@;TIU)TzqBLadhxBC6b3@c%U|#?vpi8$drN=x?<8 zu+Xo+68fVr7p<(JQJBbxeDYzi12ibYP4p~Pi#(3CG!7L6unq>zC_6~dQz=g+D&^uT zYcJtkRr4Ix;xnpAm<3f9Krw9sbjzYzS=^73e(;^Ru~wG$(}g%i3c~VQ8SF>dtdgm+ zxQZ6acVWswgsMx1;`A*u=J8SdbBv*Pqj*0mNM&k2hIEpJDT>u4J5fdk$aZDze&wVN zY!)ggFbhNY22}GNjO8{aa0g-TqMmQWBJN=+&!L0+Sj9JEE$>5;->joqKpxlQN^~Oy zj%u_c4U3{4i>25=qhd_JBJ{x4Iqn{anqowT-ZD7kMJ0;9!>RyW`p^E2atLGxi&5M{ zCg@+$)k7JMqUsPr6mE$e8YOTk6{-Sqn5K}!HG{HRvrLZAESDoSL-GpE3OP!1h#ak1 zDaUA5$+4P4<&~OJUZpuqj?)}2$7@#0t2IZ+A83x0Kh(TJPS6}Bf228DUZZ)HoTynN zCuvTWHJY_@vgQ<7t2tFp(VQlyYKG-B%}Fw>IbBZItdn(`Gvo}-Yvr|?Gv!Rp>*RHs zv*awz*>bk#963jGuAHkmPtMbYpqbx` zc77i^`TgkP4V0JJHd~zll*;lihsbq;z!xn{22R&A7|h457}w{QBi<@TvW+FDH_Q?EgH{1qf@z2 Yog{czPn0x@;RL!+Mt9)}{IWFoA4!D=FaQ7m diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTileEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTileEntity.class deleted file mode 100644 index 33fbe7db021078e3d8430cbeb5da2e63b8c4de96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2979 zcmcImS#T6p6g@A?yq94RXqE^FL`6s-WDJ4^5>c`Nnm{Bm;Kul-r!(nHPxsK>lOf{1 z;))yYE1#BCZdE9jW$~qj<%gwJe7Gy_EB>qH?U_!xhgeooYE8|&KBw>Y?!E86dFRj9 z-vqD<`=eNci)+w=L4j>iY{w;2a49b1xZDF*M6m-2fhz^1$0r3;fs}wIFeH!`7#7e4 zMg%efhCo)p6tDzx0y_n40Y|_U$P0`L6a;n&j0s#Nuv_42folY=6}V2|dVw1RZWOpl z;AVka1a1|$O<<3}?E-fQ+$nIEz}*7(aNNsrAIJR+OfpRC8Ihwho_BR4-Yavh3^o0F z+LUhI))-cozilf)Lz?M$ziaDex^*(Mj%-BQbW?ZNF;vz!3^G)8SShkLtw%St&G~Fn zvj=3-AV%r2RA~%KTlcU}R=LBv!%*8PUD;uoqnhoKf^KMCrmMSS46#k7so5QdbR3NY zxA&-4Htu9v*6fTIEZazFDcy}H^O+1SG9`1Q9@n!uBVK0FNi-*#S0%QtTwF#6j%Xhz zr8U=kJE+-?ZkfgXY+~SQDJ+H^^*yHM#;>BY7RbxI76;c<>9Vt5iyQJ1aP z?VM%1(qNc1k-oK>nM#!C7@o#6)Jg5qD>fMngpxiLY1brGqWqmti4K`JQnvTDHl%55 z1?t*_<4QBdP~9=CIW9G3Afc9+s8=y*OV=XTq4=oNCTLF0>Dm@;Amo7rvSd4vG%Pj4 z5bf;g)Lcz1+L<4?Ny#xoPY=6^)WlofXZy<(ce?3e8WB!?X{BqIaw%{HxxnEN+z6fzPdN>=qkg^U>m08YJPen zeY)cw*8w@7ifz?Y%TDzfa_qRIj^s01(%MCH$s2Wa$^+X@k*My^qKhJ6`vy0bA0!4Mm;Oot$RUc;I-JVUYUde;8S1=Wa`Kgc^_GKOK)WLCVGg zL*t1IKsxv|QcHIS!;<>RBdTFCMLx?eDVmC8*7`F({zPY=JFJ3OW3O) zSIFx>1;6g!wF>I!@5vf4tflWfZ(`GWF8zI}z&cdXN`su3_4E{{mC;(g>{YOriX!dw z8}Uef7#;K+D+!fAeazt>U;#f;bWv9_4!}y~tN^T1RtMm0<(v}mT7?zsGK9HQm$wn& zA7Uo|2zC5ptl*zuE&mi7_-7d4pF{F5VDc}qn;*p<{uTD|ud$zhgBSR>c!Ph3!~A<3 z;XmLg{}IRdPxyoX%%c1kR?B~7i}^9u%zvXg_LI*F44|7`k($2% DSF1Gw diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTotem.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterTotem.class deleted file mode 100644 index 5f604673c8cac309a845ce7294019101e2cda940..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1308 zcmb_c-EI;=6#fP%yKE_K(W18gTU#iVk;;XN>4g}RCRn31y)aQS>`rmZ{?Of_#z*lT zywIDPc;N$hW8#G-K8*1!U<>xDvDxgLnRCu}{%5}a{`>_%1r-A+T+(q_#}xxtam~PW z+|aQY9d2q^){xgwU`Rf&JzK3a#Pfx1hD6P`B*S#w_T*;IZOLFuv>f7O>%J+RZ4ubf zdB{wt*LFyOGO*ND-J5NM+SV^Pd z_X1Nswxe1vjOBV*g3_+o7iml)O$|EC=)M}%J7!xNifOFkmWEOq9Jd+f|50oDJ55US zt?jkbC}T~-9foJ8-Wi6OC|2$Wug#yfcBQEpPIUknrpAiIuzHd{Go)y88Y-YdFf8Tk zN8t{bGziC7V_E&hCgomFI5gmMqeccfR|_x5QF!ENc~ocU=(wNg9T z!Gm7V^56sbP?kN}2&BYAN~(6Jf40AGx_f%(=dbTS0IXpxi6P7m;cgQ5a9=HRNj$(q zr9INIpkq$Z;={Y=TK70P2fAD;}F6&mvYwc!} zgs6)a0lDS0Y~I5a92O6YYlpk5^F400#X7@iLx#$KApOAd+)fQ;2HlKOVR)CVxH9Ap z6=VA1DCB|kDM@}Bu@?FE%W73LN}kj5+HQS4*IzhoXgV#1Lcg$)y-=9V*P_+!V{*@H z`=)$lsZP)IlzP#D!ihK)29g-2Q&J7kku$J_yn$t`=qMQAcw(T4RUJj|pSQ$ooYG+vP=lE#ojzzE~&vuTgXD#YvCR@48crWxVx3ON%y=6$y z;6ygV;x$3Jzi~8e9j+UEk!6Bm;hNBB!^=qZFK+zb31SX9 z-2qfBT?jFHX>`akNaG|K$-$+sU|&cXzzD6Ha%w4zl5Ru+7(<#Yh6&uFRe@JXDsU`i ze%6PY6?G?_QI)keiD7LD s)7ngjI}_o%+{A=QOcDE?4vJ0F=jl#TGZ-hCCR@imQdE3`WL8W322RRQZvX%Q diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterVBO.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterVBO.class deleted file mode 100644 index 3d261780418a5f51f734b8f17734526e2d1d2be9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1092 zcmb_b$!-%t5Pj`!?7`Uv2uoN31mY0nmQfBMBOg2nDUuZnV)=;GGt-!fXE8lJ=BGHo z1tbo90Dr^jGJZbn7D=82JRZzHE@ri z^umvP-D1es4*CoQJN6{QM#qojNg6s*^@J0U#p=Ya2>L?#nLalb^m{*H*nBCpu;XYV zm6odC?lM%5qev<{5J@7*<8{Z4L!OMDJ^#Qz#wzfn=WFhyqY;7d#F%*8561yt3Y82R zgT~R|&C|UlGi7KptPiEm%zdd6KaQpy95Wd1tPqB`wN4~852+PbiFcYOQc;O~G7H+^ zC+%KO4DC1^$7$p>4_0%hgl;%ysIN*hPvca%@|B<6>&{YVi-zlGVj`+2qe3G}6WMoS z8je<}H1ME`Jv=nkzL1c^CE7D*7)?}3 zuFf2=hE38KwqVhok?VvRxv<54eIh*1ZJpy57Tn9YGUv9bkQ{N$Ln~+HzoKyXc@e?P qPK-9nhCPk4J@cGLAr7u$o8shfZOXZh4ML0bBJN|CK!zX diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombie.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombie.class deleted file mode 100644 index 7d2353f6ff3bc274d6e54418ee249ef664e1354e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1945 zcmb_cT~`}L7=9*%Oh^|RwooikOKEHasac^^DHN=vMI$L-h}5E$Gi(OBWwV>^Zm|6+ z=#9r4Z@lp1oN$hw;}7uHc;$r`>N~p$5)U^Vd$IG*y!*VL&pY$mUqAl}UZM7qr;oOJ+(bGvt6Ffbf}{slz-oz4Ah@Z>G_uH zgmqB8+>Fv;_&i&3WMI^&Ak!1Of#FM!5;YDYzf;EQQl%pH3U00LHk|7G#M$7~T8lmk z*=5%14EeK~_ihBj+Mv-J&S9;Wj)|E?bI_k&b>Gw<)hU z)^G{K#BH03m{sLi(NMxej#Uk7SZ7ET{Y}fZ#h&yue1tM-B7Eg#U251sg;;MR);)Ju z`l`bkKE|eo4Dt-a;Xv8K*)z%wC$MVr!3$H?gAg`^*EBprUc)DNtYHhEGNk`IfgGPP zlwbX1v_pltt?fLMX29@DCy=4Hg8_z{XPGmG9-7>Zz_Xk^hU?krZieYbN*cs}yW3KA zRMoak$mb1V(+wLu=_IOoeqxJgr9exrYfC}bqXX2AL?G>{@K@x^wOz$N!^M-nTCk#W zmLO+Ehnjh+BX#o}`65Cj{1)_dXY|@6JXv!ODBP*e2(bA7CIe&iIu3%$p>G&8k@V7b z(?{2XG$XV#NHV3JJOcZHHZhFSnovqUfXlSkA^={;RXQ<@;~K5XI8Ra;$NSkI-;q3N zJ9NS}er%h;8!g-4(SCjPs?t2PnU=9oDrGTomX(|YO1Velj z~g;1wM{Negg%b#X8U75zpfZp9)JEBl`?);W}fEz-p>g)x%qJb-0f NL5hZD86PHk{sH}N%bNfI diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombieType.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataConverterZombieType.class deleted file mode 100644 index 1a85224ffe8a292af6cd4f70fd45d46b761adc95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1608 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorCommandBlock.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorCommandBlock.class deleted file mode 100644 index 0e39e6c86f35d7c4092c0c96fa8bcfbd4c9ee86b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2286 zcmcIm-FDkV5dPMGvQ?#ZLYorWP$+3@JHd*Y00~Z0V>bm8CxON%(B6cNycpH8T%D{od!0QIH29uNnu)q^b9aXaj*Hs0i2NwGSeu4^jHs_#+kqzZTY z;oqG3S69SEbNVqbe3g4i7B(x525(WQUBBlwOSM}5bO$J3cBjiwJngYe==TC!?1+GY z)fh682Q48Zd2Cy9yS>4?QF=9e#ITkdHDOjs-D~W-d4|g9SPc4hMBpw}9>b;Kw^V${ z_ql-!n4}tQoUBm|6$4e=G4LABGZg-Ry%G!a4&5w@DEc7F~t{5bMBdI9)!qw~}w8gJ2ibsY5Sq94?(p*4<}8cU?P zNYV;P>e<=CW5fy*@h3?9hUCwriQ#oxb=sjXA)zm0ie#g2jW;k&62qIgGC=wsNhCCi@0|`$!^(d~~cpPh*(HW!kS&Bw6|vxkTx?PBOA-N^ue8l=@65VzWH; ECmE}Od;kCd diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntity.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntity.class deleted file mode 100644 index 04d019739c76e9a13f4d72d1279ae8210bd73e00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2660 zcmb_e&r=*l6#jbl$IK2BA)64h36YKD2OE-%AjSkDNg#XG)74?+bjdSGn<(K zic$}$^5n^j2jWR{;NZa+t1x=-W~C~nR%vOK7qzrXJ@_xAqOW&Ah@qsARP9c8zwY7+2;V-;p(Wz(;ANIIED@lopL;`;Tbu0X*i+dBu;7Q*3gr{R-D#wrUqy6 ztlWPtfh>A;^dTpg=XCUAK*jSaUQltKfpLc2IoB(iyuz(y-+kUa@w|0nVt+$+1@h#zpLKpq&lgjX2!Q&LJEIt8N4@?pQiXPgmHB*aIto#D_0M^Y>u zxM@%LZfRPiL!;?2*Gp#uQ6{PpiX}SIuf3t-RRbfqY=C1_g=IisOa+0B!!|I1Nfjjn zWjGAyA3g&a>Xz9sFgigM!0=F+PFcN=`3wiwL-YF_4C%^HLlj!71BUMA2N}KY(lExk z-zR1V#`3cjBG$H5FtZt|js%%ra%0~rhcXZPLQP6snc^iXiu#orVYoXbYU3J>jtX>! zdqjc#D*+a(cZJ0zNa}|IBWXVmVRd)@&FycS+{P}N8{q*w zhTXJccpOdiBxUv?qDYYJdP`DSK%^s@iYB9V`T}Becw5e;FxHZcFF@^xC$$t!5_8zr zuvv+`4=t(BBbL-U)Ol=A)>JpIA=Yvu6$>@glzJQWH(?|bk}WsL%}DiXy-3p4?m$z%#8%}i>{7nQ zUgaB@%D3oNzC%v=9{tJ>7*>A7CFLiKD?h_ge!*4cSG=YChIf?TaZULH?wWg@8Y?ul$-Dzg>Nyma@Il`G9TA*5Qiuk za(0+z5kh>IvX!BbKS9!V==ad6qP6;KJEfv6T5}f~joWHZvb)gPUzGNkiYMs=WAq>` zjr5i>-&nN+sJF1?V;C~`Y(?(BAmdMwOu-Ry6{Hp+GWDSmI^p(VFfP9d`%pNU`WvI5 B)E@u< diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntityPassengers.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorEntityPassengers.class deleted file mode 100644 index 7650a42ad3a4a21533369b8cf9ad4f5736b94068..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2290 zcmcIm%~KRt5dXdX8fF-kpb$_|f<|}2Fsu+2*YLGKGP2?aTUc6F$lKY+I;EktP4l_!JH>uxpj?) zq3|jqp!cTjc_PSH)fS0g79783h3gl_zqaoALA5N(uCz)U>+3{#nb)NVEVov#TFP$T z_cld9Tj5G}B|Elqxl)O@PL&-4Ml$8SM65O~`t1}EYb>uZt20ipQ0!J*1 zfOyG+ijWb%Z%J}z{R*!~m!#pM268f&ZZ+%KoGOsm{Sk(l)@@P3mLmM~t}3r1dtdeN z8sFq5_TvEQ@0OH?OC~W-l1y z$seF8vW>Q*eNRF9#?6OG_UNydL*J2+c;xu7GN}KIcKsK0=`S&$|B7*{pm?;_UseAH@%pZxSvD z*CKNcGv+*Uv=+>4RKqH@G()(TDMPnZ`ddv2S1=h>Q$hw)Q8gt@lV#EgP@ZvwQ5&<2 b{iLvgISLw>$5=#X5Mh?u*1y3lZdl3R=sHyi diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorItemList.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorItemList.class deleted file mode 100644 index c3e1e2c24f1b26717dde65e67f8b20aec49f9b5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1316 zcmcIkK~EDw6#iy++ijOpM66N)MXXxdhNT3Fg5hA5q)82@q@+ub@l#d!1J z-|*tat0o$a2Y!Hm#J}JPeY>EEp%-5PegwD2|`C?RdPKj_&ZU&Z(Kg(N6wmYe0(=FUoP zq)b?-?}Qp*k|VCcJ3~Bc$$I6~?x}weSIA8OGvinr5Bl#0$2SSply?>-wwzu!r z>%3F(`vZUIwKuBO#nT;NV3bzcYbnJ$RDDFluyk6MWZ(~_BN{>yW0fJPxa0kmGQ<5-PS45Vq5K=09fVOUAjf1tAz825KGqE?A&KjBc%DP$1nzM7Cp}&f=w?DoW-%-3y zydYkK%yG=>Y2;`v=#xKKfLNIT diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorLevelPlayer.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorLevelPlayer.class deleted file mode 100644 index a902f2e366678a80396c516bddcdd6e5777148b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1770 zcmcIlT~8B16g|_gZA*cQT0uYsQCdKjA_}C2AQh8_6$msn_=3~zP?m0Y%kH+?A7O%t zFa8VlL5&ao0DqM6?v@A|d}ua4?A|@IbI(0<=iZqgKfiqkuz;mFB#gxo#aI;Maoom4 z40muhj!C2?WF$;Um}ZDP(hSX6VF;!(C5BMmtO$mFMKi=^vtAZfk(YHE8Bk1>>m_b! zE0>hL!w|9!piI1wgt`HQ&h7q+qI?TWBHY7 z=@n7Y9J$=A)yVJ)Z#cq|wR%IBUCO*^w1h=N_I`FhyRg4AKk=_fIR;7VC}4P*Rt(|D zby|aJ@dHP;g+)YitHY9&H`j_qUd@~JhS@YKxk4e+odab{tv48EyLF4%X46td$xRI_ zFvJ{gRfXf>-d%^QwP(EHC0D{dhV``Hd}VX)t_EJuF|7ILVu)fcyTje7vO$NUi_@nw5 zdjG9L2gP=SHYAl+&KAAvSejAI6*4av3O zKrk8qjL>`ZeL|Sf$mmx@ra#cXpvTuo7O@lb#NHwmd*|^^b$m~Gi3L}Y@?s6*8liy8 zj3Ii0xb88rR1&0p{julo7k~T(Act>d3?nNefov4FWGo^V zBh33zd?4-*qqr?&3Cj}lGGr9Q@sT)I1p4C`R`H48T9Z(ea7V&A!?+WfJp+YEDMQ+L&tpxFEeS9NszK)2O{>|QpvcQ31YJc6>JALbcGT%)P4`_fKG zi4+Xea90?Dsq_v*sA$!7hAU+fyVYscbi2xHO~NF~md2Yq+%^Q9lptwd|ga$5t~aC6jC}Ho4>I#PEGtvs$XNe|zbX`q;9Yb-ix5YOS-sPZzKAwo8r} zt#(rtl8cr}juFb)^L@KDbB;oCS2BEiNLlKfKy9s6tGrRPT5YRi*7K!O`eFH{ItNZHn=PXx#Br@m#U6ovVR`ug?|dhFiw@;t<5u)E}^90b8ILW z!Bwi`YM(k*Fe+#Pqb{MWU=v#mng8A%!h~%FU*Jmx_fSz##a9w`6nu?c1rP8I!*~C0 z#WKWux!$flq)uWOG!3V^gevDX_=HBkx)@dm^fJq^GMEU4OI*`*$C=6I7N{0iQ)ipt zy#9P`^3DBwA)Ic1>OyM4<9OWYtG$=0S6z9v-$UxBi2kUkgxnzKBjkxPT6VWzA%xOP}QY*Y8jCjn)xyj|SbTi>dds=EvugBEE| zwwT(QKkFHO8F-+b5PY%0eBmDe-lE@o0t{~;K$`%KDLNrW5}iT9(SRdrlAsbnjP9|_ zGXye;;B$nYBAiJ?ybtMDA_Xu(=VfAq97jkV#*m!AB;gdF71wZ`AVzB6?uvba5W<8j z%qF5oh%JXQza#u7_``5DthBCK?Tp(9-W4OeEbO+82aKB1E#!puG){-CFO z0ujNqHP8IZ6A>1eWC~&yJk0t7`{o#WddWY%5>}?|MNf;0ApK5v9fGCQ@Wy zn&d~p{t*jMCQc#1T-W*~x<%l^6cpAAK}3k85D3>t{Rgj9hVdTeJvNo70W9E6x~ECa bFl|s%v{cO!jChoCvWUA8v0N?U{%Z0iVYsx@ diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorMobSpawnerMobs.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorMobSpawnerMobs.class deleted file mode 100644 index 32a732e3b8149b58687d44bc4e9169c5cdcf6e01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2680 zcmcImZBrXn6n-vw*<@K-jL?dGu|=dIp)9FT3PFmb)J6i-647Fn-Xu#{NH%G9q2gzM zfM5I7Fa4^H(vHsf1N;&G51sMlxk*|oFfB~R$>i=iXU{$NIj?(v`}^l#0gPZ>M;AtQ zbYnDxt2)MTElkO{hKUf8IwtX+jv%Jgay^7;C3#;hGdfbZp_bV&ZsLOwZmHer5I)o} zry-+ZUZBgfOV+I8+1}24CAU?rmD(N{QhaNq9Rf?0r0ZH_?`86pvgvMK8-HLvtkg;ct6+O(ZfkRs z4_S~^k7(_3wPY%*sft7N6uGMn2d?zJ9H?gt_pn>Kx-I&@RL6glHQg+zgQ*|d zklWHg58h<;XAh}<4Ide}gCzr}@dm?q^iH5Fc0ohdz{gltM|@)7Q`}{W>y350;#ur8 zS#k}m;4=gF@Ht~?;0vr8xDTlzXP^LL4>nrTz#587MSZ&}S%H=RukZyrRcy?Xbc*I; zZi9^|&}v%#(`W)6`}pX~qub~%RigsaEqczznrh92K)cN6E!XW!j1048r=yv@fGv47 z+bJer)&Bb?=ipKNPc=saD}f!^I7p!X(9;h966iimk$o4m9&E7~_bD_IpBz}>&|Q}< z2mIn%cBjgsJavejw9?avs*$7XhpHTB5cysEE1ty<3Flcm4evRhh#r5qrd!K+U&boR z{7%Dv{Y54?yO2$1+1qoicF3Mp&f(_;Hl_;fo0cc+3&xL>g=f)D9;|GB+Lm#FcaLtc z7Wju6kX(IeQ{$A9Gvp@8sdp!0PtX>N_@2W569V5;(uT8Kbv~hAgkSH)Ir2tB8|QJ6 zoIo$$Zd&>i0ce!T*pCSOg5ceFMB7E^3BtS3A7L&YY40RyJi@3V^<8vK_3)l^F99Vz%EWs1b;whPcZV@*>g`3`8psT|MNQ~@yP3SLHs)&;;Vz}N0{LHaazBG zUOkFIJ%({T&dbzgERfFX39RZPb>O!MZievt@DA@@Cf9ykBIH3t`5S;=L2tUHs2DX= zU?k$yV-QFUlJem)=??h*f~jFh{DD5b6O8C^GY;c?D)j&(D)s^yRMr?s6~t2wh3BUQ qkieDtws-lqjrYh4eD)Gk7w>>?F$pGlbcVQd3=2VZLmWeXy60b0Z|Xw; diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorPlayer.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorPlayer.class deleted file mode 100644 index 614da482999dc4935252c9c580bf97315f7f7e7e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1974 zcmb_d+fEZv6kVq+oz76O7DbVZH!g)DLlqPRD}tCztYDxa(HA^S4`rmCsWYc&|H4=Q zz(@5#jSqf+|6$@K(Zmlh?$Z(h!wab|v(Mhyd+pmgb3Xn4@DacS<_)xBz(5=WF$@|Q zLMn#g7)A`FF{FVO&E-!(|Ou7^1U|>&PraI5oV+5LxgFg5g-sam7-#ydnHN z-zbqKne%L3TI0T>^j%{_ZaD!%$89dTX#C+=crGh9p(%h(SZ>7lo|rZL5;o+xK{-K2i;n42!8|N0pgTy9_-WXP9pui@{i}H*m*M zOz1v*KVy&i4v(W9$EZPzw&xNTY8tM_aSc<1vFH|rZ%I)mG9*{Gyed(^Uv#A-YdNtg zHB85G9Wxqc9CNru+&bvF;uN{Q0QN=#e=(|w!E3I zRfuApsY7swA2L|Yb=#j4MQ+y`NsRqUba5$fHiS(#fc@>gl9$z-lzCuLvPr&)Nr#vVK8K z|B8hE4c+>84C+6S(SKrA|5dMMq>*vA8p@3>oT*osMK^k=er4;WQy6`8jvzF6l8SAo zAvCIQZq%EsBIZWBA$ZXp*W z5FEI1gnt1X3gW;I;71{5o$ypSL=m#QJ2T#y`R3*Q`t9=<0ModpK}AY~hEx(~G@Qjb zxulcGs2D?5!#E}sOe!!GOfe+pY{w4f8KUV-nITqitAe4wXggwgt5FeNiC5|*87#UM zua~)JOTHtF1?#rYaO4ILxas&!VFj*tr_Ni#D~om8l8U& zVX|8jQLE8pPX$WaBK4xZ-yyXaGqf?-D?hWd0Feo6RQ99 z-fb~xD`5aPZCUW6yBBV9gKu*kI{Fy)+;v?FFYFKn7j){|i#jghGWFx46WBpZ!HkY8 z$SauBaTU~`_x@YoFbqg+Mx8q~<920(x|pHYwEWSg41Is`3q3|d%{Jamf72YUbAL&+ zZm*SEO{&sRy7(*TmB6!|THegur`k~G{g?`Bk6n&+Jt$_6!4^f0Tdg*3?RO@zxLh(z z_ZXIXE!Qur^cR`$4KL-8TbA(sRPOQ=jo9m+=k+&q-Th&9sj-XZdwlF8BJYWapr6)+6sk`#K(yXIfPFYX9K%5j(JGbSAWjc3ksXWZ{P{G=1BT z!#G55OuFc}m((!HB<2Ym!BGM%sS%>0I2PJwS%R%&w1aY%c6msK$aW8LsD0q4k2q!Q nWTMUA7%N zSY!w%CpQ@)dADpa3>mg#6`J*uum&H(+rv(DXF^SSYE!yecvLv>xSvpHNSc(^N#ke>($Cu*$%W)vs$Hzmw6+wJk72* zYML;Zcb#3!qa}YUy_KHZx^`ir`#xC)$!_n?@OIL0tU#-i|E9;c1I@QQGNbLbZKSnA zu2|%iyjyR$O{bjI^~vKYFepwb2zaGt`vJpLPud2_lACOYKAqrgTOc%APNW%9J(=lv zP3bc04F=hFo1STHS{~5>_bOJc~sOW`sMi@>xRcPiR?X@}Z}p!tMbHa8iS$*;?>R&3{_NG_5iuBYS zhfNmo?S0yd&NJ$?Fd3#MP4?2|IqqB3q`5QR$x7e4z!-w)+d`$dJ`NtL#+fZnp#~GYO1gGdd@dTbE3{o_o!&8JB@BA%y z{_c1F5>kgK3Tm7*1oXG?G+7C?s0pINc!ub4#O~pgglE}bn33?@pNQVW$p?7K<_S!; zb3soPx?xC9B$9PcZZcSkiFZ&2 H#?siod_IA7 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorTagged.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2$DataInspectorTagged.class deleted file mode 100644 index 6155185f728dc213e44269366db68e4627efc080..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1481 zcmb_c|4!3T6#i~kDC;^v5K#dE#kn6y8BPU<#5iNJI4}W1qW|DscO7M2JK7F|Z{k~M zqF^-f0el`c(M03vHbrz1iKOZ6y{Gp(KfiO{e|z%|Kn6EeL~v0>441-C5m%7tLQ+Kv zlPY9f4wfmE{^$y(6{Ho+FoY^%hhef{3tz9AwlG}&*w;PbZVOl6POqmk>&t0<@yDNg zVkgVcId9sgzrZjMFKqH{u3OwL>npx%+U0CwjX};iCBe{BAly>DS`_XoFIpt&D>w$X z*0^g1=ax|RH%yPA{|@(g-u7z3@Ern_%c8`fQ_CWp-{$f8w}S zNt8@qFV-s+`tTC3`Q*1*tyy}YE$7%22Z_A(W+*cgZH!PvvcFSnxc5gm42s$GiQ!TF zkUTBjUM0VCPPOLL?NT(n1-K}_X8^WjrDOOh+;Jao}p`rG9n+g)6p$8cSS2bM2bq!H;GbI0=ISi6nQZTDw z4mSc_y&AHZ*Ki&~49mw~SccyHdfqQ?60sPLl|T&91B9Xi#)Ae}_`hHnBHS>9=S`$D z)6)#M+V$BX9QmzhC;wijgUlrY5qp{q%@AvAeLu6U#;3U;w(8uXE2p3Y% z=~CzyQ=c&?eZi>owP7mRRPxi*IEFDoCP*>PVYK1MIL2rfB1xc$jgncSHytEgXsi?D UG022O$%tVdcCRxJ5W|QtND2`VS zf1zKAD&~ zklZnLMg&5mrfqs-0{&R{l0YC;${PZ$8EVaL6|;u3sAny5qM1@ox0ZCrl;?eBz*{$6 zfsQHN)6=$FHgaCcIWUC+Ep6L|ld^QzHF#XkP_tOJ5)v>~vS~P3?n=$}fv)=R&$WT;Dzj~S6<0&~T(K*TL=IXPoV zmO{kSor2+2>E;Db&uz}=rjJ^tcD!&thjk2XO<1}46HGh8VXpKGLxCeZtZB;z$W{Nax5A#!nd|w!_%zAOxE9T+VRa zuH;}pD|>uIdWvkfknw0sw>VUfDAW=^ z(*2OLcU^Zm;^)>DcgpOejygDLsnHByC#_g_vre=rz+ziY5e@5a(6!%gb0abl@3 zhE+XW;@^a`5a{F=a)NR7!zU*lIdAeb%9E6}#Gk?!kNTe>@DqYRkmJK!TvhIf{DDB^ zPoe=@O&f2cizk71aixYNt|EvqdAso+5&Q+A2R%`xg78yBDo`K8?ujvAPU4LNqP<2? zr<0F$EboTIch7(8`JQ(8tM(7jVnqJN<;XvXNA@rjd5#HHU{>{ESq)%S4Z>7Ia8w1~ zkpHc!RsEc&FU$1qJ;b133S;O-od2&T_~}6}eU0Nj-lsGmecq3Ur25E{5#2?CI*cBv zeo}rUNw>nchbaXE3O*2j;bt3{jH|T};s$qlA;@Hi7dZ$?Jm%mMMIAMT!}o$1!nNwP f>y-Kk@ecQMeC-T#dztwgZresFYU$;&Q5GFEREHQmDkd}q|rRBW0|M^DcrCdk@Jbt*cMjwO=uWQy)r56$sp zY%(2BXvxt;G$uftI+Kh~B{Ts6Ejc|CP0mac)$5YWB9;U+Gv}v`1*2rx8H%EtyIpV= zbvvhI$+HFX8hNFRX=->KD>)^GXGhhU80l8eZ*8aFGOmuZ`t!8i3$x@Ups%aaE zN@3n8CG~lWC?YpGwICqfr7r4Ax?-^mXl}{0bHmlFY*jHss*};JS-oU3+cgKgwq77V zLXR4!>W-MU=^hhsd;{O&o32>*EUWxwlM)-y%$%*el@gik?Rp{&QqFM4#%HQc-_!LZ z4bx)jh54)=F1xyGX2Jskc9Q%f*%sg*$yl|JJzdQ0xjL?xT`7!gVZR-tR+coUQpy

VYD80>Sd>1L<9s+I*wa*OL}qAa4$RA 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/DataConverters_1_14_R2.class deleted file mode 100644 index 7cec17f6118bece2a6f9b209df6390a49002d4bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26701 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 B+Q8)aSd1GE$pDcg6O##uZC$Fh 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 J@9tDv{|Dhl#C-q& diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_13_R2$1.class deleted file mode 100644 index 49476c724bbb7a0ab50ec017f6d49e863d95d180..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 959 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 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1$1.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R1$1.class deleted file mode 100644 index ad604482595038e6ea86bd94ce395853d5c6d5dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 959 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 mXe2U^@w_ux8bpjW+<6wv)(+8L%2+e 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 B+SLF6 diff --git a/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R2.class b/worldedit-bukkit/src/main/resources/com/sk89q/worldedit/bukkit/adapter/impl/Spigot_v1_14_R2.class deleted file mode 100644 index 82aaaebc0b8a880db8f68442d78068c4862c496c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26948 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�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 DZGosjig=5wb##+B+4spDa?Gj>(!z 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� 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

  • C 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

    =nb8*ItCMMb{*!T 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%0Dl$~~1bwOVYozoAqrphfK-QE~W#88sKUwQ>aTs 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�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%0DJ4BrVIuuVXHs^{4eOMc}vY&w6?NP6vLU*^&5 z(AZ|XP|?Ws+bl{k-N-?F){WMW1C!&iytR2G_a%^+n!#m=h;| zv-_TfD0+Rs)_aG|j4Q+^|6hYoMQ=Xqt@Z+XHZM}D3u2N_O*m3jKne}i1X-UXwW4tm z)CO4}F&or76|tB$HbNBX%rj!Pge9F-|Jv$OEjI$`#hCJU0JJqWwg^z0@f3hC*p$lxQLU+{PM8@)^b`yVgs)ek1hE zU^B!hBk(8>N+f~>YZ05kQoe_DB?K}{EV!xAr^5PQvorqj?a3I|rr7#wvh`np^#5IU z#{X=zLZ<(YPqVgB5k>njbMJD${?ocmPv5C_Wu&N;ud7urG%4H~pw6_#go>-bdVL;ok=n=4pc>M$Kd%Ac+Af-5uFl^Qp8RNZ4Wdo2itmxxWqZx zU?vIU@qnw6i$IXSV~Ok3+jCbba5E#Nf{^NI*sEApB%KA1v86?s z%XMPPtOrr)Ol)lBTAf&F6uN)p_$K%Ci#Dv%ETb(`Ycvh%2;?#v$buJau`-ual$tbS zh9F6qSnww((&#tQaX4yJbfPZYD7iCbP!tcWLX(BPxRYSshxOdbUCUj^=SEsPOxp^u zDp51(Rv;xcIAVlox8ankDJScDn2apkC}jnQXp^oA{fE;42GLrTlF9 zGi$lvFtUIh^aW~>ojcaXu6(s&OTAQNfmlLg#7SYKH{=RT4`hfdk-~a-$S6{i(Jq5^ zSWXcaj9OFe*Vz)q4!1DYk`hGdvK-xlWT`R$jYAd?#8C-;eHFq)tg<9e&($eYo;}uqOhC$fVG#V3T zFWBS4Gf7vaaE7@S0UN9Y5jLT+$m-`D7N|Z60z4Qr?=21(NP*+wvDY+PeP2AkHc){r zeY8oX=8+gpwoSP04ifed9EgI^8<<4VGd%qifQjqpK_7WNg(^t_3eY(Q&9EJeoROpj zNT&@fbpUYdgsk&y6?@I}j_jD%ZR2hIxvcj`hy(Ypt0p8|Ha8};7kZpMLTp9FDDjcdQ>p^(6ABAtVJcoTS`i9 z%bm?_we#=$)Viza+ejGbuK4!x!&;ed3oS;0vk75MZR;l!MTOhTm(H+S^Os58xx5}> zUF$zExyILL-g$|RfLxIrV2ODritEJRP4W`ORlCB{&v~u5sdKI(^`TXAxgvGwcu>k8 zXrio{I@Bld1JBjF*}ONa!f&DbRo~Dn`j&jY-J~X!U)@4>^XJ*C5pW zG+DYd{o1(cVD22&Kd7UO*#faA2$X$8ceAjSqJmvsq@oK5_J_#ukJ0*o2mPzfdV4cB^-KKwCy4G}agk?vtUUqa@1GD|&vj$J zckAQy2Z%p-5bh^Ea^&~h;j&Y)`4jP<(@g}(-<_F9J=bGk8v#*`We#MX&!-?80JY|V z$enBgT8i4t>sz)5n)Of|Jh30wf;{iv>_!N-q@7_pZ*fu=vZJ98jIg=)`oHz)=V-)A zaW5Tc2s&l22=q%OIxhfohp982i31QF2_4Y^zmzp%7zK;5?USY%$#jUMt?N@+q2S2# zq3rNAkzYE)-+q6azZU8(mfVOg^i&uSmSH_7c|e|`pej){Rf{|zNNfi*NZ##>oufOX zss+>o^bm)eKBP*PF!SLg${a?$%Xt+0?$LGxNHICkto96PiOxxD2{4Y8J)Fa1JB|eY z+p4U#Qi_@TwY;@|^%c$k^gL^7^8X1nEh>{rsDfyGIRF`oXruvcpL{V1C=<9sP(dH? zYAMwr>L6Mj30JcXMiT-3Vqk9O87D zD`vo5EIk%vR4835j+$mWPq&Q{g`Nwm-L=!|?SUNg;T5iHXafB8?`~s4=vCBf;Q~xv zLncayO$@u8!^h72$}-XEh9xgo&m#rjv-VPYmqF#p7^@VxRnM6EO2cKD$04`Jo=ZJ9 zOM7po`6%*HMg`>DU(M1jp~h|8RE!c@UCBVtMhjT^mU8mxBL?0UdL1prxD8zM<(e=a zp6*2V>deLZN1bzw}uh{+Awwp2-`Q1Z62bO8Y7VaRS2$Xs`e;oh>P|gKz`vffh}0! zDfPmV12L_>IMjyiR|9N zw$ke*WP7R4XdrTte`0HVc4ZB)zMgTB*m-3IJvFGsq} z=%B2GJu>MDDT(Y@T~>JMZW{oxrC1s4j&tM)n(VLwV^YJr3?b@976|%V$EH9dD3zh* zPmi^yudQ=P>9l!T~Rr)vvCDzLRVNGfML$1Y6HJT=F%BSO79piO-b z!bpg5+FqH_o(GXJfyn)PZ;1EDWM&z?e+p0@9f0=)(GgC;{((8?8ALw+i9 zCTCfrbZ(uMxuh|79<8lw)?Di1atSwuk+J^OP9qC4nM&p*PtBqc+R=APMY9XaE|OS@ z#UjiPD^}rnVsThpvN+9S$2{n-uS+P=`*;zvkkfMYBZPyDUkJaqRsay7 zLjf~nyse30F>2~0g*8i}9n#FJrAi`{#?%C6lmrg>UgARTc+)oUKYquTh)Z_Bp<+~| zA&`+l@bI`xfSQ^$?D>6!K&64IApc(uJ_6{TWTH|965;sqzqxmi2D4ChjMf-ebcf>e zV&y}bu2h3GHhO(nf0{x?H`9d#VF1z1MNlojeGCYZ9?Bd68etcWBRL|dji zx~pd4Z9{2=ijtcGn{~ElK)I$!udIx)UoJ>k1UGOqv7I+=h<>^&ENTqYDaK_K-i&YI zpURZjtd_XnQR7fTq&)fc(5{A8Rza2|GAj~}Ra<$K2UCt)H=0RXmUbD9TkI+}V%V6mGUQ5u9*Z^(HzXN8e+cBGzw-}r)934?o z_I>B|(zBLCT@-PoC%6h-bcjK{OOx#>=BZ2a597{bmv@3UmiW8fLRy-@BPGncon!h< zBn7m%!n}X$k9V6JWVCFtezRY1WIoG(Ih*4c`)~fBcX}zROuzqyJ&bhLcl_+=(n1;H zHGKGR3GzoWTtI3GPEkNAV{&ZD^N$?ROU@oDCg7cGoE?t+yeccFS{kP_B~<7~*a!D= zB%Il!eYNNfkZzZ8c4OY{V#>IC$98%-q1-oT3W-j=^^kQykdw|}(SyLg5S5(){c*xCQQGfu zhWx}K)Vpyo4O%~0L(j>G?(GV6gkk_8mkhL|+b9@m(RnH~hR{`nSUx)f3QkEf<_VHt z8Sy4!M4O@-_QK!vguHQE9e;l=gklnZD8u~5ar*dgmzQl(ah9&HF^TdkA?1GuH2a^c zxA0d-`1&oD&KCdDxUJ2UCct8AT4@pdEjbOcwe%c&_$D zH`e0Yh5^fN3I7shMvI{O2MCPCom+Bz-;YLVk@TMNe$Bqm)_yyie2e>be9IUOH4=n{ zXbhS}JQgk)-W68C*qPu!xG1>gL^n=^22BOsgks0SIK!Cp51sAt-$Ox5AqDTYhxIvHt( zh{R*cVXqRQuL$^a*0r#q9HN4934K zr(TP6V$)d6TFh2rl(_xaIgu-uafI)x?Gj|es#4hWtRGq1i_dEk036euC6VaUEr{-R zl1^baj@V$~%+Jk<03PP+{oH8&2Ns$47y7X;q7$x#q8N@e9Oi~!RORZ~07i?}h_8ZG z0xE@IH6qsCr+F*fyIn-&OiW{=;ubPB{C(avva0hruWu^$LaM!U7I%9?%4XesF{JVO zK{N-xG|R-<@-u8G(v`*i6yrPy+UL56@hNyQ0~?Xsg-)A1NG80Lx6L1>O_MO9oI(0e zU2`U(&nl=>@8Y+{F2IBQ{h}z0#TYxXIAR&>DFb?>SIB=KqeRWc*mu8*hUKeh{&#Vf z|FdXBoa`NhEe!39P5(t~QIVEMRYdzJjmzi_&_YubQAF0Fj22a>ha5%`G7c2MiKZuO zTP%RPno7>FL`Q|EA%rD_)jf?Q+!Nwpa|9yZKDDzjpl5> zK0e|GD3XCe<&TCnfn*PQdY{4Xfxcdr?5Y*<4}rtMgu`O(_vtIM4rdIw9-EL(I*~VuFn10~Nlz)*Y%_UPs}3K|aZS^vF0@qIXf!g}o*pexFOp^W zg)C%J;8vip$ZGdwCAfS=a37#v?1ODn9vyWXMRZ6tNZ?L3G5;17rAr&)qn|z+ax!vx z`6F?YCnx1(K{uBA?j3O(S-Z?4<&0Ep%Nh1IA5EcMC{-Z|sofx=%zhfDvF(I)h?Wcce_ zlE1qCL!UeYQWz1RxZSJ8oP;&GWN}W>HqR}@mN|-!MNvvy%wJ=`#UA%Jaff6#7!-U2 z&oSbz!3)ACMGkkxZTNFX7w#oOlNQo-yy&l3M4YV~CXvEA$XT6k$U1k}ZAW)_pWE&4 z&7*v=hd*TC2MmTz;!7oL;sJDIIK>~36+G9rocr#0FE-+N=fBq-pA=*I1VrQgL)|{O zL_Q!!p3~aT@cHzn`Y(pfJnCBx}&LOxF=K1+w@)rNGpnM88f`)vB#2RA$=dV!z4;THf6~)^J zPZgctoFnV~&c^G_?hK65_Ekq~V*xXSLUv)H7LXFbQv&77xebFQ$kFeow- zhMF3tygZyYrA-4JSwTfbLGgEBWF(@B2pZB2FS|R%8R1=$zW>?fQ_juK{|$}hxxe+l z?u`pyso$1ZolC4on75cO+KQAyB{2lKBc8)>t7bqXZE88hY z{%%k%jI#s_MkXnYQaYP9``u0_8=Wd+o8AM>_FOregtmzCG~^yLhz#V!t>(ug7KpA z!t&zse)mE1p!Xo~;P(J|wzy^5Gwz4&9}UC|#0=i-m+q79pX{6Lr|F~Vhra#2r@FVi zhuUY|XWf6%_akUEm?MBAh$E0ASRT|KBoB@sq8oh+?HaKFS{P!Ek8;~1_JP>|VAB<<4TdqCl10TKY7S6H^4dcwEuh6}G z@=EkUnFq@fSs8dqQuQTjRc&)E+*Z3k`4#BS5hlazksY$A8FWsuuhU}lJuI6+_n;dNf5DU2K~U_3|sKcVZcq6YMpGu3E!jox1Z^wMN6` zcqUdminQl$WfdutooMinX4OK4yp4W?A4BD)S(<#-Dkx{?W8pp)nl)r$6wyNCG5|B0 zGPM%58cFzCJr96r@n;QJ&%TD6bcG@Mw(q4uq&YA7V#igFXip;L7`&;CZF?f+MQbw| zg2#QW)a5xA&Vo~pT7ijb)Vi#+UXBiZI#qJITJMITj$05nP$pd~5uJ{OWOfd|k=90& zG>fIwUnWMf%F6t~ZZP6An>5U-gvFZ0H(B!uIdR zba$Niz74x`pefN0+ZNXvYY&ZC6>iz8%#_I(Tl*pkTdHlgQs&r}47yZ9i!CcmTJ7t6 z%E!eZFUhhA0>VwJ&6RQ;Vhi^Si!h3~YSG`8-$%J+uHp$6%J@oa2c5ucK!T-N-K@Sp zn2e8|yN$&}7b~0Q#kn8HOoh|8adYLDJI>3E76i~>e;?(s)n(u+3O2UVd1tTUES%i3 zS01UBZ?S7?$yU8&x8bYFpjfO97-1_39krp;ZREeqtu!--m*r+rwsaj$oQTQD?21f0 zZAP5fn@C^*l^TtoSfZ7!ox2aReD%;>;pj_2&#oBejFD#da4RAi6fo`XGu`Y&IDa3k zow8MMy6OM{3i6r4mvxIy_V!e0+i8~?EKGkz%ZBptr?A&dg}cawFzjVVZnBQjcTGxo zDx5z`)nHB|MCpo7xREpWc-?7rph(qaj}Cd6gpX?SLY~`z#+EBb*tT6dahl!}D7W=! z5kQyN?2wFy2M_P#Y#GDCWvk$> z>9#~^i6Q1ik3t;Qu)Vld9b&9i8*t)N6WLWod^h!cOH(7lLiLqMZJsY=vF;0N9EB*g zt^D#)z=uqfD#3*o*Vdg^V{!HdNwYqxPI_)O!r1XZqsjC)@&?=BzK6Lias~a|tY;<& z0hx}M)R_u#Q^p}J0u!TODwRU8i@(fJBep#)u;M;cqN4gO<=Mx~)+M}psi2gM$DZPL z77C(Ws_IsbWjBfbeHGE_tQpyD^G}5aGlRDg<>w>;s{C=)@mM>8R;?plZ%dI?rWYr) zuPpUd7EV$q6+^FKQ8r?SKEj+t?5UDX$Ye9GSnJZIU&l-~rPPZn?maARJ87JyB!Y6`a^A{4^b`suD=^W zIB}8WPwFu?9zO_BlNdlZ`s;^{aY9XMV==m%fF_IhTgRK(v3iM`#-X)3b@Ok3$@IPa zDh4Z6rf$)l{HRj?teeSm7^rT!ceWZhd7-)CmR1~Pzk?gO8bsSvtb5ZgS{AYVh*aX5 zMcXu1VSbsb73V8e)VgEFu5scz94eQdw0gRv9yg0wEmo;zTOLw9p)Dg6Ji|HvqjBs| zo)FzBVsrEJR}Ml4F_;;bif_%*=15wn&T`Ys3!kqL!);U7a#BV9OlE#{2;IzE2BiL5 z+RGfSrN396j790{Ly@4_FlYDQUcujoi66Z!aorVH`1}s{DiNJN%%Y`E_HJb z_H6|~e)3h?DmF|)!)a0v;$H{HT#l2PYBNiyGrBhDN5X%mWriJv%$$uC3AgDP{8vjX zucSfq;`pz8Hj*nBmLJ6(9{pYXCO_SMngeP}t;5f>UN|;iQWIw7kre^8McgmRd7Oza z)qhjseeaD?OJ9c_!nh5W>NQUb-QJI^ti*A>h(DX zut`axiws}*o8BsNf#5r96b6LWFd4+gkO>4Jy|7P(NjC7zC=`@sm=?k;iVFsh{Fs_i zeoEaSkW(wrc&Gt}7HyQOUV>IFUzb+VphBaxHuFomR`@3&D3Xw@(@Of|AKy2cMV z6@#9&{64V;$-wD-GKkjjBy>(u8`XSa7wURh7pgfrFSIp!H%f=fwThp0r^*Itr|Jej zvrGH(C8!z6 zj`m#ME)^IT5$C;!(RMVp(|=Je|0njOf&iWsBBuG9Y%}O|Gcw&$uo}()*}|Nds7xs= z(J6{d0S#kH?J#R6^x~P`RDKv^62T~~7fjQc=2StNBN~Sh{cInvUieEl46Fxi>~Rif z=+nN&N<+LY-YBLKvVP>S5BbImH!X0pJ{i#%TOjD@FSy$6qQ>|vF|r{Zq2+Mp7+!U3 z^8sK?t2)BPz_yt1g2en_C_L~n0c;Ja0}7Wk%~1J}+9p;fE{Vk5K>E-x8_yH1OeA+` zWsK!CygOjV0&cSqRCoU6G?rdm-UX~xysLpUbEsnezMe(vr~L!cYaynw`h(MhcwPU` z2eE97p6|i)-xH$wLy6aUZX7pXdt8b(14&)j%1-Z>BvzdwSsvj(A^v@-6oV;O7W^_` zv3>!FwEx4}yr`qArGu@h-M`54s?y51;z%E64;sX&VWtF-c)xCig-~$Ovau%nK>`_D zzu|%dz_YX@VXG6|j+S;i(x~RkOvZYce!z%v<9AX}3de`!k)v9d(r={Ym@f|BBs5q!x54L=u1)WHDrbgi`zcw!ncu(Lwkbnh7ofSPCfC zkPHW={^Un6;0)Lt_#_KR_$EePJT#zzWQ&DJLmF>$YKYkEn>tW{jkoab>c7m?$%(u?`x> z|9}^6QW9NmWsB6FI-E{4vfsk;D)ceb8V*vM!zXX+Xb?=&QkWc4dr;~q$CI?EgR6#v ztDT~t&#O){vCvz@YiR#D-)X7h&N5DPWZe%JH-IhdoQz^iV_#7fYh;a4L#f@e1UB(t z!CqBcGNrV>#R@Y%))m6Sio-RkxEk4c1;_ZXEIO-jt7sKOJ)1TG_kL4J$SW~0$9hu! z5<}IZ)APd$TPu%+qozA`Ww_@t+o$(EZkbM13~`2;^^&kI8m`nt#yE72r&2N9r8$xA zfS-U7aIsw$tvNM5W|T|(hu%A>AwU#6Zy#nnPJ?_A<+ZuMH_J+Mz}zL)I8{@wrbFxy-a^lA}%TdyrlZ=p*KS%On0q*6xDTajIK2 znYzl~CgvO?%P>o(5(wtMH}n{o4x#+0aN7^lw{vkjbe=Z}C3902e;%)b-hV=la^bv# z9`<=Q9%+3eKP$=j!hg3PwoCtM#^@Cgd&DdB`ct9qSR;1yL{$)%pJ5T+21#=(GfaKU zKWxByh}!!}MdBTw>V}*iJIagBs)D2weN&J?q`8KMRhMs>;4!^pE+H;VN6+N>^P!h` z#OE#5e>YKw2FI$Vv`~wh6CFN83;K_LFyT0yg6-n`oF&JTE60t+XR`jV~rX zi7dRO3*Wwrr?n=J?%m*l$&I7a))U6QKWqX5(!{$M8JU#7BA=ZjJde>K%GYwk*Nxnx zBbLo!7|vk~$P-EptDllLPH8Kc+H4r)xh20DQt!sqzbEjSoZaUVh{OB~s&^OloT5Kq z-;Md}zUnzxe~^a241~aNyE|^!BN_f4D{BuXYd_+Ad6wj7njeCpNO_@Y_l*{V;*f#rEKRExSmf6i^sNI3Wr!4y7(4y2Jryjm2Vl<% zvHlArQIA2242k|+pHDX@KA*pja0Ae7iiwOV0T zXud-N25vX)_FRX&=dERUJC-r>uPgifVNEJgla;13ZOgKT?xy-KPi+P4_U%&Ut_2d1 z+a5)Ot-7=#_jYw-`sP^Otu4*`EtHB8ZaD-qTXlTR;j%szCAiqt7JH|7vh`LaDsn;R zV?|kepaivL`!QR+jhzNvkAYil@waVHJXaPM#8Ned@O5>)GY`Qkj=X2n>g-bNL06`S z4fue{C;j0ckE}_o0Y>5d@>OKvwD`1!=uH$gldXQ;&^1!4Mw$ZxH7X5CJQ9;?U~e?& z3OTPq`QNyC#%S>IN{Y6N^QMj5ISY(W7wGaz<+}wgS9MEWs~A(ZYj;s zzbfQZT*G6ceDkvUbvdt#wVjFYGsUC>+3`ow1hq$AMM;WGE-14?_}P6GT+9z@>$6** zgSDC0p1V?wA%h>973$7%u=C^G;);>?Rla~^HosZcei(iErTuvoq{u0UCUwEGN56Pv z&^nia&U_9otap!tR5mYI?60ui&`EsN@)088^ppwJ%yWXx!D}ECO;X)pXWxR0RZ#HB zghi>}n5K9g1mr4ydc_i-K~NOiekt@!KYCyWW88KB3_xt5(JS}S7@{PcVddzNbW!W{lf#p=R{w9yWq<>{hv0PNEq6gTiTib^UtrUZU2St z{-9_z=eTBPlSYA3m?%jnlWTI7klsv==e7*Dq$hWj%@Rr)_qwv_#x(DdLl1n0=qCET zz~5)A3SDt)gaqaHO#oV97~6Z1yFZlR8k1#vi|x9odb>ui_}W;8~%g&_H>X7+IzC zk`ROr0Rgd!^(?yCG$9I>#Zt+}nkMVlkda*rdCFCTpG6@?I zE7Bq-kt!7H4ZT{yGuCf^)pDcb>22k8Yeby@7nUD}IZ{iovE8*cO*B`SYNZ;i>Gzz4 zflpIn22(_c=|rE4ZCFIeX2Wm}2`ZO)vzxZ}D2XT-%wWN5=?>Ly1e=7@{?7Rr{Vi?W z$80wHuW_liF%};!ZPjF}O$5FnrwY6=Iot+%L>j)}qj?n^^tjnsI86a#6>QYxS5`5#4Fj1-WGN8UXJRe~k!9zpOFhuvTS1QuLQ2s$;Cc>#xdEqV!HLW&Pvh0}WIh8~MY z2dec)cs}-2s5OU(^;v=@->UX6;^0WUm(Ep544qUsP$0+3Y6*nPwf+}ehOi9g;Fw`) zB#vmCB_bu?^X%6`$?CARVFwj9(r_ag=N3W{Y5~_GtN6?4iarIli!C$e10nE!L5}!g z%gzEnyg4kV=spE(H$`y-OAhfk&s7~!k4^5ICxefa&#R4vi9pQvOcMB3F|Pc8n#+NCGvYe0Mw1$PKu)_T^TLI)fZzL%R3ggV0jKUSBEvpUqG zuxk#K4`oJ||3&*G(y+5o}FzaV0ybds1IL--4}g~9Lpu9*wDDSN@r@G5ps*YHlD zunp>Xp2MLKNs)DPCMS2iMWK05gfTXsD9r-z>dI*|$@IM~Jj7`V)Oz#|W{51RbQH-C z_Fq1mFk>Wsr24O6zs z&lqkV=y}fH^_?(xZ*i{gZF%>I{eW%S5Lv-NRIlL(hUwIPgkD361%)J1^ufr~ML`s< z2FVjU!QYq07F|;PwuDpLIY-7C34e!i7VP1Vd<>ei@Ay5ou>eT=k<(P_#h zyJh>jGw$q12n!k6$QY69h2wvZb5sCjqN|{DWsPFSS?9cb>m4Ni3qp^F;xS8m(;rAG z?guFlIC`K+H%=@!MI48BTy=h3SzA}x>FxLSR;K?AZ#d2I!I(L8Fx`j~bCh+4;{bY! zam|ad3MdKh42Rk5LmkOFC>kmaC(pt==#XKU3)F<{k2f4+KExs$1QpIL=*!2dWkkcq zgG}o;zQvY;Q^y7kWfmS&Fw`*7F!G2s%mCsH-aB>&U>13BMXDEiEC&$7*<^Qp@e=0q9fp1TwZ3f%q8DBE8SG{ zde-innK05YBTU~)3eaS8Aye|z%Cm<+sIt#_X#q%%yrY<*Od07zP%+@hD0t-|sl<~f z6Qj+3H1%4iME!uQ)sptxJ2a6CQ7cuVO+?~SBvF^{ARpCg()R52@BKXeJCzW80Z#mZ zd&j&)<7`stQeL4QfUN&Op{ zhI`q`;e0*>>RW`yd65eDuwCUHg&%3-D3yH9W-6>%wv*U?r5;p`r|RW*@@jgvs4Kh2 zDMxmT6pLe_&_SsuzX#uqJ**Ag9pers;?g6A>VbJfe#_4!GF_L#6d3nABJeQh zI{+&iMn`}sR4*0<4_Re)ES$6!InP6iR;sJmi820)@A%K2&SpoFxx~BlGHC_ z#(xoFw;;)AMdM4{2F(NBQ}!}4I)B=aWZKD@*N%OClJxC~N_TJG~=~YCRXrVO?g03wWs=Hm|&wln5?6C2o*%N}HTKy$sztMCi5~<;tOLN5f~! z4=z}CS_$ww_sxiO{S`mLK=|^ieXQdi_oJ<{_&Q-dcV~GPNR}V@P-2B$T&0pFwvwa| z3U$gU*48~ObDHhEH!f0DvVfnfdY46?dIE5G1@>WnG7)(OIfV;!v`DmaWF|4Ua+YIc3agncJ7nr9r+Xdt~wBZIM&>L7qfw zHC!X7c}0v#ta((@UQF43pCKLIUnw^_Rqf(gyrs79W*kg_G{NqW&aE@TzJ3w8cU~@w z*Rrh0Cn?7)d-JS#TpPN`hlTjS7QoaS!Z_20!hUZHfbPwy54j=Q>T^f2JM4l=^5Fnd z^oGUX_W){q2!Uq3dG#@bL|X%!&~10YfX!zxz^3PSAi@U`P;N)EJ<1*V`gj}Q?STl? z+mUXMBP7|HeY+$y@C^&iTAq2|Tz^-|9j)5tk1|ZmZXWc2jw6vfxgzg28~N{Un`t&_ zeCRL8w9uDvK>a_g@krP^IsX$cU8C|(j(hTql2ihLu*Kp3)B-z4Vr=7%5`+mW(#Cgz7 zsu?q*p7xAPMv+=_L6V%sO_1T}04(nDN2{@!>59Xn3s+v5q={%kdZ!{~<}2ZdR8vn= zk8hLvOv_*25h7vMAG$3}!kMAAo{BPzw=$v$KtbBAcL@dqNeyC8!DJGPD(`coHQp`x^AQ~*=@;_*#5(e2)0(RP- z9Y1lBOkH)Z_`2fRi|woEQ_@OZY$wZfhS_2-;M&}KV&S}1L^`Rev;AoJez2&t>)K*Q znoV|E|8O-bFW{H%h&4RI(%MYIy;cJ(vHM4Sgj?m{CdN$;6kp7>uS<|0_s4n{|NJhi zag7o3s9Zj4C54;YY+KX>A64r*mH^?c_c2II75!Jgb3WS3D*_AWRI{>Ba9Xm;7vPeK zJ-uwM*0+NSm7nlIOnx{!C&H8Lhre7;ij(&F#C{3a!4k z9%Xn=wt9sZTU&GXHElMGRtmLnsj|k67-jXHwW96s^tD^7UUL172`tOmpJwuxuwZ98@Xr3xh-BnZ8Sprxq~}O!i#(Eq1!e%2##P2Iq*AUpmdWPC@BA@7n#QWx>UI375GaFn=)UnMy*L9qJJ6XDdEmO#z5_D&5< zt`E2_pOn{51uhwDTk6U0+!FAzB;DXoT}Ai}!d1M^!~F!^@f*0CGvs4pRX6yTJ3hep zUgbNn{Mi-|Ih30hXs)>J6aus0(Qr$S62$b|;>j||WJl2;Bf`PQGc^7({QLZ$V@zv* z_2r^jXZz0^J7o>OVk9gLZ6yB{UXbCQts>ewdQ(w(&A*LswnZEl0F#IssYyc70{{xi;&4 zllS6VR%sWatXg)iB5;2JhKL)=6uFHPRN(+OFo6UxOt~M089*y{r9=s!42n?*Q;3@j zKoZu7nF~h}mmnfTR)Vqwut8x1XoV1nnhMcwzO(Ko0;alAH)9 zG|&Vf3spvx9qE8Ga0X>glpW!KF<=I0LY@)i#02sJ?vd$#wj&wB4v0cwlIjH2qXU%y zlSuU9YoQJh11V7I#5yq!@B?lDYh*VfoiGQ!0eC15k}ZG(%K#k|53-$TJ3P=0z=L!x z(hdu>1L#8e|7`yb)C0UBU5k5s1I9rilJEj<83*!^2n0RQfJ^`ZQr_5G@PQ;Ke?boz zpe4W@DOc130ayn$OWGZ9OEMr0#X#B}RF4Z(1*{_JiF<$nWdUtSJ7R0Ww+I7WQ2xSS zQ;IJD5$PlLmUuuMijed#7!Va8kIXOp{A1t*N}tFl;ud{i6>68rC+Ze|;0fwe=othk z4#-3D6MN)ir5Haauweqz5=2t zZjuv^%#5l@-Z(SXNpulejoWxV=0$Yzg~49$9rGf-h^a41yZmP2oA4;?M%4H* z21$e)ZiCd=KNd=a8)<{pXl3%97&q1iyfI-+j2JiO(%{Q4iW_W0+vqqpLYfs|L((WY zh9K&O)i{_SE5;77u41wnFDvc_-iSSBM#6)#t~h2DKP|+LyN+k#oG>lSPPh(g0-Hc5 z)QYt}KbA_Q9chEzcr>O)!~?l5WnySj6|XsFl^_}~ny@~09=}X#{S!mD6-Se_k+TuJ zk*pD|k+qR+jCrha%xUayY=y*Hs1-qzrSWkrRl1AKx zx6W>&PSl06t_tEN8(@oAZ`}_?QJtL=q4}E@>-a8nc}1&=+m8IA3iFV;!Q|b8@h_^; zxP~1HmQP>but7LgMLE1!Sf<88ZjSuYMn;I5txl{tIj&nbn_IXR^HE_A<2ZN5qvb-euLWK`Ax8I(>x{em}X8gn<0w@^9 z*a~R`E7su0Cie#2m}bI=rdp?gK{iqZ=JAhaqLf*Y%d;;@*4*n+hDxzwZAoi$r$?n^Dl7-r{pFcFaf!6$ zdOKcvSrIw3CJpxEg93tG4SpKUR!VZD_+Ul!m1MN3(s<&K#6;x9kXtRg@?$Q>eya`f zh2%u3^7tzW>1axVto!a_Lv?MBv!j)*PR68*yd=BrkEU2dnHvY#rhO^dQYW{9(3u^> z&2fj3$YDNIZSSxdd%0QD_Hp2!pbyTWg zzf6iKY(f0iB3r78-gQ7dvl}OFn-w2nM-oq07diZzQpTiDhslg_?}kbx)26}b1+OfH z(z=cFTGOM>i0rbN@qBv9Lp3v3Oaf$_?S+vjENwz1y!oPvZhv#pSLJu-Vadc7kl*YPNGrRF^-gnMCxBBo(%;w97pY zJ%*dq5ni+IfS$ZbnY+EcXXT|;-ErP!WX9|s8`|+Ks_*nlvucK(njWa@(1~H1Z)eI3 z)1snAmnY&6sJj|Mwa%({TN<7Vtl;(BG$#;GGm;; z&2y%5MV&J9V&1oiQ~5?hF7{JrZ0fSM>P}#?|8h4`x{% zusMZx!^f?Ax~u)z%yx=OLz5K|_`2Uxf-f~GRZFe;GuI}q0A(7PhhXvtFQ58}4KIfM zAJ&2sb{$3))t6`o!<@@Eo^?9i)A>{e0gL)XI}U}jndne$HIX={abRb3%5AQboSC6+ zhgGCmwU?z4+lww=Qn@TzTXt2JwFbnf-r6cT{Z`WTpC~F%u3MMZM_N1lo+=z3L-XoX zYjN{gqT+cNxz;Lg)6oUl1=ld#!}+~&%ZiHn@U1tpoN@6DEq8{jbQjJV>{@xXlcYz- zE}hu!i67PM_SYL7Ev@K|-71Lgz!es$os)gXIIswfjIShr-MBNAnTZk``y>eEHV?tH zhML2T!m5a-`$Z>Xj4uiJO7tAp2}rStteL;2*d@h27NvcEljcJBq1IH}dQ_{jQ+-vyMQwAsCdnHUP0Jxiht96Ke?o$V zr&am8kg6qg+r5)&B||4^H|DL%JCwXTo#)+9^~$xIJ1)~AmfJ3~j(11D6@Amf;e_Po zj<4dq8bgYRw z#>BQcv2EM7CKFpv?t1pU-*@lN*Hc~9)nB@*Kb-6A^XbWRdtE&B37+^NS3) zg^i5+33VB>)Ku%Ksj0^eMawc~)UB=*l)}srif3iL zboJV$c@Olst!0x>eb60d1!x*@arHfI(3kq)#=g_;G)I-q(!1zkyn4mV{%LOKlrr^* zDNK^XEjVb`#Pi4vqd=d1XyjZe*DGq9DRY8aO*=PWY@2qdiMImOc`3KHwN#0F*fJ!F zwYUCaC#!BZQR}T8VFYU2 zO|7W}__#GNWO+h7wYX+`HZo1@V;g71S^O$nDckZp-06+6Po0Fsxn-%>Ek6Cp4DF1~ ztooAm;Z*C%t7@d58TL!uXC^DqRP7@Ld7DbP`@#hrud}nhoGCt>uz4 z7Hz}e;!~|F-W>-VD*aaUt?tV+d0~oc&sPokO%OGC$Lv@!e9AS6_l(RZ1rY{XYTaim z2f<&v28NO$hk}6*!!~VI8PdR3FBQD~fZF&?*d=q_x^-lZQauH`ZeH9L_5|3`0vcAw z3pV|A9s9Ermuxe{Bs~?Lwb2CrCQ$s-^K%}9ZfJaZxLffjJd6q7&M@!qPD5?F_>L1N zp|htYpKQ0w{`^X6P$tj>*Ug`C0K$^zXrrj<6kUUxG-f{NN9{gIInm}pqQHqhEh-&x zva&=iH@Q8aA-%21wLrNNy8~w(8}^7q1?G&=&AvK*jjzbyyAJfliUq4ge6eZKrdKzI zxyh+9NrjIvw!MNvHh5GPlxk>UN3rpwLVY`Db8@>UFsX42GlV)-ZA5G|XWZINmY9?` zKcvluK3%5hdS!9k^{=#aG9R&S8qof3uzl~y6YGKQPY~r!FJS`^aa8+`F)*nkHQFNv zc4+@PZuPh$x4xiJL4xZ+MyXoBm0fQ)HSug*t0nIT-$rq7>Naa}w4cD?IK>9z`T`lD zX0qEw@EU-UExiU+fC768HC&U=D@u zL0Us#C6SXMA8ClZkXWh8YSs`3m!r zOrv^OK42vGyp`H_454aN2F5%Q`!e&Cy2^}Tj5B$$%z7vFWY{ncR@y22fag#Q2`xF& zlZ96K>^kKKv_bb6s@6Q z0qCxI9O^3~QMroN*<*E=_o8Elhw12RLh3BI9G&L`Cx-@?l#YLqR`PVEQYhq)* zOyPNH-7M0)I6(5WtRCG(Rc2nlR9YZGLq)MLvs4Cvy{ZY&JT0upztdRFe5O8^exa$% zdrSN)3qyS_?vr?5 zCsKvZ$JB++r4lFnX@x++360j+Lu!37=S0RL51E*vCz<4F@Xuy7chcmN>f?ZCM zPG4L$L8o2~z`&r2mwOR^>|+PGD%ZW}(T%6c)_xQ5OQq3KNMGtqIP}GQQ&?QmJV4 zNhi!XupV$^h*)!E$jIX<3CqH>XW5 zIv{4|8}ntB@96L<_95{a_Dul&LAu8xh1{XRipB?xXcHV*CjMqUy0NqADN; z1h|a`o!nM|$d2vtET+BiEM{Nuq6?7O3B>)DlthWGQpAY?De}bDDWV_K%*lc?%rSxs z%-Mo-zkj}$8k6``8Ke5-8ngJ6?pQv5W>Y-t^r<{c^szo`^f^5%^uawF^s(GBA<~_| zAR0d__t8E}2Z{?>mlXP0hfXu$<<)Bj%74r#Np@M46mPM!rx;m=r(O#dST?}QspiA# zsjfrj(ijIQs?I`o6(zue$pg@p=J3!1(pV{j*v;jaB~>Sb;N(5fR{=WKB3|xpPZsp2`Gn!0kjSV z?W8rPGmFeMP)5$z_XR1ZRk0b@7oEu~xn(On=D~(odX5CKq#1A;R}^W=;S>X!VD~sW zta>5kt5cbk=guhQW^X~TAy%GqL4E8U=Dj;l%2;b&`{%7ZGTXYj4`{wRa zKnUyp8d2_YPYY^mnD*(aB0RhM`5Ju%#TN~KK+yvIk&-hpyVvTm)P_VTs&c!yj#?;i z;3<`UXvzft(V{UddxG=Ec^S)>acywQl<)D$hN|o5`7U-X%oElSu<>Yb&V z;8$p0gsxvpSLyEITjNVtx{qPrR6_AvqfGlvBWZTY6c@2Ts;=a%0pcCEo8l+Nch(OG zzx1s>p@dSy%a=#wSKoJhzwh5Z@{jw8F$5k(cfY*<#`)AZOWa8IlfRd62MAFfUJFGO zzB($8WurvBO8?sPLmj#*?k{}>I5PT4*c?oSTR%GQTD)sIa`_qX4;!K=USbd2yi#28 z`f0Zh8KP!iZ|v&6mpuk|9iqRw81lV?s^R_SmeRWp@VmF}5s$pQ_a6B=X-g7U=-+x`uzt`Bqe}r7Xy@y?RzL#FOzNcOYzAJ9!zdCQR zy~1zNy~=J8y(eCfy*FIQzDHe1zE^H-Z#@ORdI??mJ$YRdzxq7Iyyw1Bee}Hk_{e?T zddGdm{^0Li>WcgrBHrnG-h2K0^*HZQ;IGB7heC=DAB7^1P4L+tSUV3FXkZ_r;BSiI zIUi7{*Igv{S6xiBui0U)?-ycT9|kid+vtQ4=iL#(Nbtz zp)JDf{0H*9zR`O^;)zXl<0)fmG2J6((0f90Mr`^=h-G&tnsjv|ntXH9X?p*LxJUK%aqMJ;u8w+c?VT8T1xV*8P9BO<1U!WyTS! zuxAz+%VnH*ZL+o}ob1=yIX_xjFg=Snl%|{R-{31Q|IOJ-otCm}e zF&M&lH$qn+6oO=JX0f)}&tTwRfd}s+?<2>;AwL0kNFzK_f7KM_%e;UwSiPPFNVWEY zZ{s{+1@hN9RbnYD9`tdBpWzIX+!ade-SeWfqM$*CtJ@~NgVF8imxJ%~k1Kr%B zwZA91S~d~rb(yq$W6h7*D$@D_i>PoUkO`(5?>XJ9T2bATRL3S!$px)>G?<4_WD7NM zJ)P|my91%dP{$@b#oZ|kYNYcq_2Spc*Xw$HbXV}#8@)m3@ci36ODh-#-`Yuq<^Mt< zSZz86CD*lFz_aQyq}b^{a8>Db0_$XP18+8A)>X9;zKT0diE_oJl!m@TBn{g zB+BON_bDMkaG(bLC^xfdQAm)@66VxxL}*fhl7#dW2y%bT|NamxN%d?o<}6{D#gypI zaI}bTH&<#gC&^aq`)C}Dgqeaw?-?pPUcrS^6n*-Tg6iO$Ka8*31CYW=(4MnvqBm}q zpTdaHSdL)Zh~UJGQ(*}x{@S{hMpRB~Djw_~7w+~wQ_&Skv!cwhsR`IbqShYqpvE6I z$2v-DXCyZu->&#G@TBbVOOsl~jwtEoRZ<&+cR1Jb3KOS5Ncw(zS3V6x@_hzAVyC#M zsQkHQ(z*nh8o`$1$>Q01>Ev2f3rS#Hd3S=cIrSUyO#{=+S)z+^+^JBeS=plh+rIK( zP?f-hUpW-QR3TD~aqF7d;6Ns2Q{P$}_KXa3dZ#e-KF0+l3<57Bpa|yP&&bli`^@yz zCh{iopX!&L34<+=_-Tszx|PM?m*vsjOULapcLoWO9AQ*^K&U>9^7c4|hk8^4;&)($|YoB=|wyNYGH%||1x=hk5b}y{_uPGJ>pz#6 zRu<$jYMMFBFn0SlnEG?VsEV(S^O0$D9|weYWKa`puWyk5`ddU< z_j{S1m1?hePQ3;c*9ck?dE3cf5g4BXrpro&?Au(nXyg($$3e$eh*zPED`81O7l|UB z*Gb0VLdPIw;`@w?jEjejt~b{%-^&5bFP_R_d*qDN%_TWZ(Y^@%S7^|fdb=UXnC-m} zB)&WqMnS|9Pfn>!)wIpM4{`*WEQ84v0gh1UaFpill%_g^2!ZTID@j7b-^f*+5oU~w zjab<&7}hehO84d57Kam0B*u6>^7(%>V+q+CO1x2wnR4@(JP!Ugtxl`5Z{1U{E3#T| zlus6(SguD-Mx0`Ubtg-Aqixk}b+}6MU2`0Rsxx}>v@2B0o1n%~M_a0tX{flEJ7xef z0UsFU9x|TrMc)t*#pjOJc>;8!3H#%XV{b^(j0IC0&psM^+!JOS! zQ7!?qt-KJC=#Y%s1LgViklF+adTrF}MB2V9+^yl{!6+-G{T%hGk(7AHOyCqZo!w@; z&DCksB9jWXqJKCRzrth31WFBDfy@A6yTY^DdOtqGXvw+myG~Kgu6+9d3jDTSUAPB* zi90^D2d6ov`hKjY^3PHeRB;*MFPTo>@oG5ciUVl$PO1Z}3eG2JF2{d#67`}KTND!4 z>)o+sa;0(2K`kG}B)Dj8QOv2joHuF_AN5bA3NVv|k|(7;NTAHoSbm#orPO1WHB`QI z@8&brI|Im(_689b6U$XP)S_Y`m-xYfxSgm}>-Y%cg|sv3Nr!co+D`ltCH)sk?>@6J z{7SXA1|x^qu#_hJ?G|3>)0BcMnph0cDx!DdH(XZ!8)jb^ZkZx$jSTgh@2n4xq^fbf zCi-RRL-}%`k{=zSMXm867;Ev%J$_4f?syZosAlewouS|Y?3%~(G6@QN`T8~=1b@&; zN!FVi{#`u~$SIEHhg?I0~MyI&MiGdF8)x^>A9n>8^QV z+_#Exl(aJOK5&F;U;QQS*jr1oP_q`!Bb`rqdX<+@eW097B7hR+x5L~_`NF1w~{AwtlFSrtOpakJlV4kW3PQn#bK()Wn=dM*4O8B7gtGez~ z#{>C_4J#R;3uXF6$5F=C#m&pxr2W)NF_X}ybJ1&v5#?N>)z{IB9_sPRb5HEzub9tsaPK<>-DRbx_NZ{6>p{9tuwm=?N7LOAe(1 z4)7QB_w@(!-vg(DRDjDsYgX9y^q&L&0XYe`{>>r3TOOPX-dk)tADkGyS$tcA*zRV> zl~}N6`%J!oEX+OJcy?znU!w~%Qs>IyH&13{e;)?|k2TqqRBKX?p4Q@M_ZfO7XJ62u z)cWQM_Sx@v1`SEIsNq4e;qXSCk`!IJbrAO+F1=B(oK7+IajA9c$;IhORoMs z*IGfVLX}3H#Z?@c{(#af_3{`f7_Iv%sGw~;t|;AlR*iO_dF(Al@5*DCS(cORIn z@>?_Z!;_D@J=eAa(^jJUc2IX z3k>8KSMfMkuUQ3g6#yMkZ5?Y=0Ra_yNJy(KU7CEPWbekw{d?$=J}Vi^+UeC#+`v-c zY;?%n1{q9#7?`~|G@X@h2P0j)J%#CCEk}*FRlc~!!cGV68u48PJ;Gm>_3MIsFb-m6$-ltaGm)%B79s#4j7eA%Yo; z{{@iqQLbp7JH#y{%v?yQSc%M#sVkDWlM`MH=t-yxBjYQiwsvjSul)fkXR)#Je%QjNa` z=ObU%vQ*2xXk}x%{Oyo~XX;6-6-C%fSTdH_Nb#+{Mnh4^nG}c>C%i4Lg7#}lTs6*K zURZF-({!=f!5PELICfI)<6*)vox#~$K!#A&W&uVvybBen{3!f`9ADd}aFB*K>QX_T zmg!*i(Z<;;cSmLmg`-h6rFPV*B6QpQTvDzSRiUmZTqsAw;0gIBz?1p6!rPQ1^wVC6 z`joFd*kZl{ji>-8U~gb`838DeV*V@!D&;Y2#nt6k)hLyaj=Gb|*Gt3hVG5Yct<*cz z3#u;F3y&DCtc>*lyJP-qP~m~|9@m{Zw_x3jM}Md&GJItShDq1vZLa2sihiFgxBheP z)R|~6K@nF;mEtJ2ID@9U|2kw{DFdZk-DrDDQt$%|?h%{JCgO})*7^|@8VWm=sz_)PY zc}X`4_4IozWaBjE={F4MrTr*eCxOG%lkM~ZO-ArL5#&A6Uu}g>_<*NLu?!!AYy8Xd z(-bG~Iy6Qq9ucQnGM?IQ)NFd7*f6OiIFD0!x!_@V>_FAwXld2q2%suDeop^x3{7)r zOhxnN06~+={Sb_2ZXt|_=bHe~C~gQz?ta@JT%KwEmUPNHya?O+Sxr8>=wyzgLu^i# z!w2+3P<7JDB`M?l)P`qhfhSE+bJE2nE92xyu8*PLV!MPm6MP?*>ry%q1S8VfoG(d%H&8lGh==S!y}{ z0jcJhSxfm{ZSR7-Q%!lg%TCj0(49N!g=lJ0%7gyf`tAfWy}0Rrc-Kp z8~@FQ=h}nivw^(*;w_f^R`E$?TIUv@#3vD`&(#H6Tq|Whi~Pkt1Op( zh+S)Jk=toeoy$QRyTG4RH)~HZt_@}Riy3+Bg~S+ur`{ZTmPa+!5IcYA4h^EBwR<+` z!TRy%4_CcDMaxHNM4`f+CBWkyp07^d)bB(1zcgjh%w))1Wn_O?_OG!~w!1`7KR9Hb z?3rV_LgC)glCHP%KwXi%?{JMbTgFTu0!UXvC3}C=2@a}BMm|F0UtQL_x4J7|6`SKf zaE~4hFTePq8}8ZffcxQZ?OtrdzB6X+`VCAyZC%2@6B+FK4OzeXv=0b%zr3PVUHUN- ze^8}&e++~_nsWvk8pD63mx`<;4_t^FX+-(K7p6sb@SF3xh7pZkp`{}Gdijn$dPC0F zl`rato2p=2Hsx<7)t>@V=qp^(wL_L@FGTVdQ%Yc7(Qqs9YW)VeG=C6jEiPu&T*HcR zq2;-*OZsEgtmF!D2W`>-^m*D6921-xa|EVj6C8M!Sv4Vt_%Hx};~5b$5%WP79W#Pr zr#*UgoTh1$J)|=BzqvV%SxGpCg|vGlWt>F0g@bOEsaNC-T)q-?kw<{SE7D3f7^}#!`o-~F7Yo6KwBY(p`a;A*?^R0;mCTlm(+QXQk#)KB3CdNIzxkDisH+yM z^G1V~ZK*|shcs5~_IZ>yoU4FM@wV|7%cduaRa4*0`!rB(cpzsrA?&=AMhoD`oE7YDxGS>Yd{6B!fBsdMyMf*NYUxV`(Mc zm-=nU&a!Q?_1ka`6L<9OjXEl19Dg<@eUk+=Umch0gwIlSlKBeKgo@9PkRWRKm;kx9 zL-h&2LWJ-Y6W5|gv*%gA4w@l{GEz}<12R7qE5AdZodK<$U%A@(pK@&*ki|Ej z+7vJ4>xvfku2x!FkEX*Gm*Nar;;GD{!-QTXwTdLlF=m%_43_dkmfznIy>Ys*>D{Br0j~Mf6%Te(yuZ`^!qMx!!6&0@JuUB6Tz(Uuwgvu!kU;tY5@Ucr(ma zfK;A-lXg>3!TWbdu+L}>!@a(@(qzBKq0zQf#at!P&62;og{_%pUJk@dwEsAVz+hy8mx@qd9y@l38_GIPZ ze3vNMPjDRTEZot`XUPR@2~-VHIW7uU#t2-x$fnaPgn z7xZJ|^u_TaGHf#0QX+AT!^h1p_g~IK&9>a`2b;tX`+AG70|^YIyTsFEm2iU?DU{Bq z8o-}Mo)(?vUg@T(Er|OSzHJ84ah7VBHc=MN7@#W7lzWB7x}MiX6{hQr{?HON1SXq8ZSA7DJQD(5P`pASK{IYRiw;i=6HV}@6T$_K zNd>&cv3<;OLC($b$M5+6S-48*C+gClg`4tOxc{`vR0Ux6Z|{4h+L;}?B*y!ot3_0u zBN~LXGfgs9xGA4@MiE9DdoWIH9WfJL!Zo zU_32vQAsuYlFHVO`FNM92ZCfZoFN8*muzb%P_r`JTod)@;nYkUWYJJcAIFHnUiD+ z<4DhHX@NiDK&M|{XwOdlZ4R@^r!SsSI zRj)JJa+Q*bp6pf)S$CF0TRQH-SP3bU++KC;x_+LS+#i4P(^YXn(f{ppZm!gm6d5coG3+$QXVOlm*-jIeDx1P-<-2?3Y zlg`2|L#LViDi}SZZ4co@0CU35k2x|3!+Fh z2w#kVcn|VP*i}@)g;$!1Ea;kCM6iGU734cF#U$}^Nq2c+_+2-PoNAZLxs)uPf!ywI z5&5UTn`ZYFnfxgmXO|Dmv8Zx07k`inER(k(GfZ_;Xdw0Hu?-a%msB3wv?8o!t{ctr z?Ycq;b7}u8F8e!yPy0exoEop$8%gS77=OSNIQ&tl0S{sB?3B@0*xt!)QlV?&|194c z1>q*1&+2BkcYl_*0aLl^xX zyHaEw#x5=2$ju)v7$|fb;v(_G`-|ZS?ogX8)Bx}3F)*#o>mkEys-q*__x*VX{U;0k zU=2(kG#YfAW4|L~H0m<+WV!rkcS$WaFp@^LIbzg+)j@m35dwYGKsiSGuDQ%qX2^w* z3#Y!k>SC1U6HPHqD(Xf_4G-$fIE(P!pbPswEUSL4)zZDQAWrm2G;(zvGv_i{=9r+E zf_yLgTKE;dT~8y#V(~#drSzH_4U+aSqq{CY@ha@-KH^(NlK4uZYiVb#2q@Vjs-*F3 zq3m99Ca-W_#mWX?e5)2h9*@9BD^eCO9?D=5xUsmiGs#s0N|y9K&Fd`>fDakcOS4nIZ9C7(1ygG{Ukc+3}2A;aI__Q z6zWHgR`<2KK0MJ~o?)zPGI@W-+n(}W(^5QCR0UyL=d}4}B@dI+R|;+Ze23eE9ka}N zp!gFLD&!es>nu%Yk&0-esKfVlBf0)LtSKI61iB(b{;{e*-9oU?^b7P!O3%-vf!~}F z$_yc}wn$v{{1){d`whWGgL^^5gEY?>MQ~Eex|KSaB*ak$b>8<-9^eR^@Pxg}wOEy| zdw9{)TMGuYTn(H5MMo}e!>x4uG%)gf8W{g+)Qqa7i;eZaTV%C=rP1p0&KWnWSCATf zN6`%@j3}W7K~Yfl!-Z9TW*R9JhqxXCi^elVLMa791OwqW=KF(@w?%P3Qn4WWp_H+m z-^ZT1J_L_mVyd^k&>JZSg3f5|N>Zko!_x7Jm@9WRzKuf;*+St$)xp&wTu~*Nj+lci zdFw_{=$h4gnAPeDYBudOf;0~?)7eMztew2#y)?c(B(P{Vd4p!u89jPj?t`d;HOrdL zL68smz;w`-mUq4NpSJ(mh05Y3y5T9V>LRq<^g_$TrAHmLFPs%=IIU&TWa;=b`?{h#@p;FbO|x_} zJ7JvF_$}Xrs;fIlN+N**+IX*1ejL*^H=dm|hd>cNTz&5m1 zeK$gL+Y8IK6T>SZ%Yd-Ft3aV{Vsn0d7;wCJ@waKgql~Ph_6_Hk^Oxl6FG)2S5^%{t zy+ucgsPg8dL6`Mu7JOPRj`i8tB_$&%!QXmxTE?MA@aYI)WmYnvnzVz_yQ;a^O_1fX z*~nr7%^&$4?OZ`-$^gQ#A1NNx;L7TDik|+rr+oTt3?1rso(mcl={;J``X}nPJ1=qV z*-LT<4qZMEn?!zv{B1Pp8r}FCuIb;|#Y0RS#!i-B#kBm|+Vu@KeOuXIifu4Ka=}oxW7$Or0shFuD{N=meL?)2(8)Z$jjK}6 zeAivKj@75vd0)3aEOqn|aU!M}vR<%$2A9t1eeE7wawM~Z%i}()EZ{M^!wkRCnb?&M zuWy@KC18v62C;iPtrN>BgGOZ*M0S(iy%~=p3fdf*F6rvS8Ijok>6k%bHf-$loe^<3 zEbMW2O?CavbiE(d4ekhfoq?8If;%w^v+fFl9EtfFy3~Zz<4a}p788495-j|p(6@X) zF@=xy7+y>k7-i8DenzGB2p_DmnWGb59=2gL3+Y*w5ZF^8dG2hvxBp6{6Op8pYWZAd zXMFPQjsBmV>i=IboyNa-VUF#lZkes6re1H#TkGNISgwX2Ko z2ha4~+%o4AW{cs%U{Jo2gG+t8>V`+gASWZ~LEgr``Vv~#s7qBEg$EY*FrMn1?wr2& zbY7k92gMx7XZ&YKmcW_d#yDdzl^NP0Y0up6CL9@!pxTN4(ULXNS?X!oBYNre&V{%@ zWH|(0FiGS0u;VY&usy_RE*@5bWNt=hy`AP!$0)L~E3A;gUwhL$*Kk#IpEed&<|yNB zCns&)8IvLlOcTHqOGPie=w-7p?j|f~bEbv@)ZLz$jIj2JmQY=AQs9lynIsRFT5Yvp z1Vry#==T5AWY+`f7jr14H&tSuxX(&sms?2lI^RzOQH>#3_0|@!*;`f7Nk7V{G>x$| z0r!uimdnmlJW{#ZwW@SzXYvjj;8H_z55jTRj20#oeiZ+x#om2+-(e0f?)oNRXcDG| zux8btXry#o1l`v#Q$W$7l?pyjc;1TbTqv5cEHn2Gq~~aAF2Owf3?i=5d0MHd3{(AE zk#Pio>JSfOle1lbWILASH?vC1n;F9dNv+P^&hk{wmIMZvL;LD+=_Vo+pO@v2)qxE2 z^fT+Y51InPSqRKC0ZLe`+;ilZtKkW9pxZl&L*eGPKWqMdZ_pI$D1Tv~P-NyP9htl+Pz> zJJjnesp|I?Sh*}LSf?$hH>tSLTDTPxMZ4-ZI!AX{xg1~-&~Q11tm;V~wyklLYA-os zwvRcSeBeXiubz6_X`ccwKIUpfH67-BP3SZ;NW@G}efxy?o-d7v&bZ4DqRK305ePq7 z+XxP>f6$^<^9~t@SD(%z8sIkGG6@l=yjyI6o@>c1(MR@DF-U!fB0WBltQvJMjP+nJw~quj%H_f2jMFqg z+*$TCiVX=6e4bQYYXvXwyc^vR8@TP$^X6V7Cd4y;L$e%bbR~15J2|-bNO2ICaw~Gb zTN1vm2Yqdz#)hSku~G^08Exd9=LoXYlr&ShU8;Fg%Bhi{JPSoDCm~L?w8J|j1uh~l zv*3hE&|UHNKR)b>*!P{A9#b_5b)$TskiC*c-o&6DWp87ABoJw3lMDzI56xoVaz4iy zh#KY&cYy}FdTifq$>wq4sG^|=dW~yS^2UjJl;M0JHAn7^WssoOWP)NQ(4uy@cObsL zhSk9t6l@XWSe#z$!wrSOh_^0KapFG4k*JR!9i6-{e!KDzRs8>{Siv|fM;%%e8u?W zQ>(nH>K?5jyeudc&M2o(VGJqy-?L#06wA=%&ujDP^VA9iZy?m%*u|2rD) z(Ad!Y95a0&lCNx-p+X6h6-o$4f$0T4Vp59>+SG(DDq&d5Ql*p7+qmxig>LWzzwp^+ zx?Je&uF06YFBK^EQ+`oe<=fpu$obKoinnF+MXW;S4HIlJwAslj)qjG?8!}KoQHXsOL$s=VtiOlF! zVWB&D<4$9#+V&6NfkMVL5lu3M>O+V+xv4|=#nMELlU7VGDW^FGwKH)UAfJ&$v$TIt z|3Lrb7l8|l#bDS&25NL9x@1|>M*S2JwyQf?^w0ei&IS_fM6Ikp1W#QWjRMC&UEb%< zrh8#$E8@!a;Q31W29&)K?IP)j<$5(ygwL-}f4p6d-VOX7IxSl30udtFUSpB&lJ%O* z;Pdy}q8%fOV09CM(Ge6Ft}yME*J*IGw0;NU;;>E8nmBC9@AYD1RM`4VL5#T!TYfKs zo>Jr?Wgdl$Ik^h%{zl?7s8!07!a+HN<-t7a!*ZBJS4B2~1}9sfG~YhV3M4wF5G^;4 zivy=&F{I1Yf4eZ%j!$Yiy83}Y_>$H^A{1vfW{{6iCeD1*eTNghI9(2%WGiRq2+-Y) znl=+b$wC;~0u1mw~XJ2*daRtKGwY~w?1(WVsV8HFnHbBK$N zs;*KrBF4Ebe2~dDCa%-a|3Y%&%5p2uqOsGd1@hi2Ucx&OFKh*wu2$Le6t0nK0V8;M zFMmZ}eBX);ocnGeEC6BVa!lQw04EjkWvS*TnsMPCI2J4eVUii6acTzd7i>b#QQptk zx!j6A|1k$op{KU>8*xG(km;JzK17TNUZsxOV}i=ip#G6wtd8qCRjD|he>z-QR{X4T zk15Zu@m~oCDA~oQEGL)7tmD2Z3cU{Q4>K$UNP?a_G~Y^7k#|r=1QaoaUr|R6QYr*Vv#dp-Dvb61?oz5dHMNN zk9`}Y!`#8ZeZKFrMYb;2fp#0Q7x##5$7`-uw0rC-q-30ZA%#8Nyp;nK2ycYGyUdP$ z8x56U!#5I|%>yHzBZ!wf$55EnsfPU)Y&T5YfD)HC5lIFf#a%9NW~n85Ly31}iM#Us z7HVc0?^-NDFX$j|WSDnej~>?xHp&=LbDwtdk`9fBB3>$r@nnNiBR9 zkmr)G&KHQjs$Ed;d^|flY>A6tDS$KM$x^BR-GJ>L^@7q?*MB}_mqhun-F^(aOTh{+&)G(c;62zM{lnV%yJ-Jh8u5Kmbs3;c5I9Cnk3PM(T7QOM}V79Vi`CT#4pGdptlW3A9bBpeD z*5U3Hj>HCYC*+?5o~N?w-pB8F4)NonH#VPT&cV$y`Cwj?i-i*VR)8O z(6iR@$&C9Ny{S|YWQxegm{AF9gNhGE)*|x_uh=!Y>+>g)V!i5jdS;XblIw4v+APh{ zYZk)dd*nL1r#o~SILNZHQh5roNBw20W~XuiJ{n7M8>0ZSEK{wPAUTEn#Cv{$WExpz z3;om-%vuB&JLJMe1;vQShrD4xcCwPuqdNN}%4#;t7zYYbO@x930Y|}<;tRV!4;E-Lz>1rsdSzWpFT6aL9Op z_ty>-#lR`#Bno;(6X}p}+Ra`C&<4|zy!3(a2IkloIE%tl0tlQ&O|DT`yvgHex@f(z z&;Uu7lI^sF>|}$fu@yv2;vLH13XOO~EX32VA*=i9Kxw|-T~+U*ZD-Jorg3m? zX=@P9`%+bLR;dn``Vxoel2ux$|J>b`p39GV3B?7g%$#POd3mdf!{gD$Fy*d4o-OD{ z{C#q(Me9^Hx~*Qy^qnMV^{gr^2r5$(7gnVozn3qTrTYGT*Jo?9a@XYJ zIV1eVrboLra|Y#DqV|GND&r%m$3hdGmLN4>Qjs=7yG2+_&lWu`(3-?0ZXFRf-tA{C z<(XApmkcKUxZW!Cmw{h-xEsB>|hi&mz|*4 z9NMBmC{tdk&?Vt5aSbC;7-W`_k6#YOB|hGP-TvLRtEgY#6uB;b*&;sOqHSVq;@3=l z27f~oj{tdiOAomrK1Jen9`-rOeJnflj=;8N$$E@dSet_BO!3&5pEu5yJEq(tCnuvr zzYegCFJ&(u&Bw1`^^O4E<8{pg&dn20o%?gmee&xEoPV$Q|2o5LIbg>;5@0>@`yOz; zUOqgD-`nuKPF+S5`|@~Ud(k`#^A8B7Ed-jvzDX$|nK?Cne}m|NyQg!vk6)FjJ^*vI z^3cMT_zII`-ISfMU+n^0iH$Xb6-IB&CcmlGoesZzjlL*wU#>vZ_Djy+zRy$eyX2+> zBf%}*J<4jB9aTZ)unElmn%=ue|CkBw@Cg`kkIQA(f6W!Nn*kwnpVKmkPpITSjo(+b zHn%Yc+W#BB|1Yj&6JQLyFudd^7Ya3lK75HDEv-0uTtFCm%Hx+$u%veD21DB#o^QB) z`_pbeo^adFN9iCrH zBcJK4P`UQ-vd(u&Ge>^_oPFDA4q}7sr?XB44eCj)K)FC+Z7u|WIna15ZoRP%sxEK! zAb0@ct^sf&u02n{VMv!O9hz5yrnNw;uKz}n)sem`KXDB zR<}eAH|_|u#@O?c$Ec={L*X)3!=5jO-=P~#oxmm5Ak94lF6us3p$+w<<_yEUo>^Le zFC#2Oia=C3TvK8Mi@~&P5hX$+wFib+YCB4(Q5b;9PcC9;Ik`zQ07taL5|}-T76Pa7 zYe&m;_$|hfRZPLdJ!vZ$Ds4+hfVCd#=W1I{zk69{3i49(|Vt;`MdQ&KNvQPSlnkOM}7AQ)-u=j(`^+5 z-K3F^P>m+bdM}YGiD2A``~2KbH?sdj+c(8W`fh7>2OV1#+qP}ntk_A#w%IW|wr!(h zcgN{C9owAjnRCv}-q-)Rsk*7}rhe;N?|Ps0;8>Pz%Re~7gKhSUA@&`9e*Aqw|2Gi_ z6zn^~{E^>-MV!7~I~Q4JZQPW|1=*wwat0K8!*BQgal!J*Q1(NtY;K z5LzP3v`F`Nd!~Mh zEfdK>r@?$`i1chvNubc6(^HyKF=acA-9tgEAskrkWAa2$?PJ0NDd`~)qw<*qwe|-P`c*xZDeV?jF`*N^#vEPQ66TtYLc0}Vgtq^Ao z;@hu1i9kZwS1AMsmH4cQ+0ZlVTa&xTNUwF&zG|>mm~{rn@IJ&qUdVIQHr*|PKyS!% zv^GPd(mrr7Bv?MO%ep>Nuy|NLiaOaXP~ZlbH$)DyhsqXpU@7E1EFbA*Ri8813|tq{ zWkH`T*b9UKrib{Jdf*boJzN*VWmwcIiE&ad; zh&Z@xWG?Eq@Vri1K?6w30leW}MtPpa)agqu4 z353lEu6vDzJ9*Ab_UE$_(?sHB>$MVGY1|x(#MR7}wj>x&-y1Ajm^)s39v}ssAo|4J z9ZF0{Lh&#$ZIXO=kJ-$L)uC1TLZjDxGO#rtAVDT?*sUu%o@#QUrGpK2)x|LQ)5@;p zD4YddZJpig?Yl+CEkzT%LpyO3&H8UMGExPKlf6?hle6M-RwhL=%k*1~73NLO#H%1{ z@WDyhX5WO!6*X4I{kC_yRSuc@pRC$p<7Ey*FRQUtHF94BEs&#kjzsJx3Kgbfv!+sM zRztQMc~w0Lhwii_tDUC1Lvv)DSa zs??}jmNalIT&mF8g&$M%AVjyQ(mt}JsY#(X|9DSNP*|v2ahiIqW631W$<@SyUxiti z$_%R%lLt4KtW6cGF0%VhmA-WB;e-SBRwKOsQkpjx!b1Z+bk))%q&&jp`SA2`1V_4U^4gDII%LBnOBht zJDbCFdkcyt2wu8F!*xzTv=IZ*^RGdjP%bYyw(oRN(%9_%Hruc`|J=FKKG<2@*^>-C zGDu!E3wcf;DM*Q$KGuAUJ@E>2LaCib|F5YrW_y33m27cJYZ3gurFLlwo)@J{iX|f~ zudywAcucZnHJht*?S8Q(kjrkp%=(wahB}i*KGuP%dq3Y>L8yG)OnQ>G&neN43gPFCLFd-)_h_)%t;$-CF+4XbAt(hZMhW z6VUNan0DNXXd!9KdPg?+ar<1d#hAHdINmK)Tp;UzxY}mD+WV)wdC>1{lAfEiT0k4C zW)x~!OP13RQk%b5(nG5=&BGsVzpSH2)F9MG(>ub=VR zs>%nc5KMmb91Z7ma2pREeXJ=Bgju{(65H@c{pQ6waTFFy;f?+mZ{75H-wprpFT`8C zCL!kYou46tPaL*e;8K@aE^N_byApbF24vLu z?1w_InBx2>v~?L0!|6fAhoU-v+gg#Eam)_sgXMQ=(0zlOzjED zGH=c<<5n@Kq29;HEZifTnsaI}kL^-%j(Lqc(0bCJn%G010$qD&?(VB+YL1p?Hale= zxM){uQHFwPN_Pc=muNhnT%(7h0{Fu!kYd_kb*K16Xn{nl@h{s3x=_40IsD4;Fj~jE6S-zz-|;GUW*X~XAvq#@M@z2Lv?4A{ZXPFWVf;gz zFEzEH{9|2j-m1cTrxRZh4lco~atTe>o`_q53C($*P+FpU$L_CNmjwhy5ibi*sr<8k z>|NBUz5;lsHq9&^y-(r%vVF%C>uMjR@7euxf9w;YLq3L!tG^Z&)W7Z)jJ=}qr0Cwp z?ir&g&zHfK&IUVmz$tE96q|iO{5!Psl|FAS{1e(Kg!|{gay2Vkv;Q|kyIDiq5nUaf zpK+oq4Y-_14hE)-f(nftoF`FY59f%Ux)u#}s99RkI2J@*%tL}3JTY_8vZ!Ot6iDPA-9at;eDQ27K zmO@}B#5rc0fqXXMmpn7{#Gc-(swWT=NX@V`)5qkBu(^DGNt92ianH+Xp*gXwMxd^euW`i`sVEMxb|)Go{0h9}e8Si?+FbJo~loAG`Z3G*323o9-eQ?yVlJ+QX!H!{deO)d<}!ExFh+g15v zrMpt)UUNk5WujL!p%z|r^z3eGZ#51JcA;gj3^->=Iw`K)C)ZEa-XD{Xy~;t=FW3Q1 zq_FXxm*$tO)m>+9ShSmI1L*41s0uvYr#Xr%QbPH;eui>9UZo{lj+PE|YmlU-Jc-cD zl8kCawz2-yd^o_oaGJ?PKRXaDzcJ7m0b&u`jqNft>Y()<|E0W%g z<>}ZD9HmD7UGFl@H2yq5&BFd`lDnA;?{Biy$Z~y$=G_{LE~cxBdqbu)R@yFiSm1|+ zY05_DR3y-vKJ3GVZyo|W99PktP5GNu5hf+r;LbCeq}pJJYUL@rm})|H3@c+!%j9~g zr6T3B^B9D;0y1QGGp2{9thUDZY{8%A7C9aGU_CG4*#Lwr9lv0gFj(TL3I{4r?dK-W zzD90X*E@*(_ra~Tcl{?NNq@z~03f~ZUoW(*#hb$mS;$o-aasf?Kbd7ag*Y8F2_SO!Rr3sC; zC(5)+)Ch!r3#(~vA&Yd!IuOgL?S8#9V@!}S>#yDspWX}}*c`Ea|9Wsk8cKg0W&cXw zRZ4I>PXS9|g2th$buZwXl#{ztH#>uEmJfAlL&E13gNmFa*h1g}lX!s6Y;} z58cfAO9}M?cpeoi7?WxSM!<@U-4_Mr0|=uU7RE27G&kUNLfU`;p8cjT*)`cH0pjBs zU$v^}V1&Bokpqgy8@{m7On}c8iGe$&&f^7OjIVsvDzAd=;~sApuj^G(sAULF7j^Z- zC4MJ1zl>KJ5&Y@&4zqZzSfAq`=J(D`_5numf!g_~e0pH`sanE$dF1p+@Q>zvbmyAv z9YJ{qkGm!W#e9SaKF-ih`U9I^HCrMGO{QKsD@>|pjo%I#Ttp%79tm8C<@9@?kix9r z!T$XKc)98>Q2hjh@IDWLe>!1A&B4XY?*9P$)oK&=sLFtML?!b))zyOGRj<|-B^pT@ zIE;l*KoW&kAu=X~4B{ZQLI&IqY$k!Ii!BjOcF;C>8#5?B63OH>yx+i*Ggg1{HSNa# z<1O34zsCnsNrXBQf}yglV8z>(8MRA8;W2RF_ogF^L5Cc17^i-!2fwN37vEP~qPXY<=d5xPe z_SmboTY`eV#qq+!eOlvNbV|c?v7W|-kt|}Yn|b&hBmvW5oc2rVcwe<`B#+smSoOag zZ>4v+Wx_C#Svp(y$i^CJO=}>{BcwDzkElsjJcq|lZ1gZ$_5VfWg|T7yYoJ1OK{PuK z6Q}?!|KPa$ktv?0R}2+!A7v0s<=ezYCXX@_$x?t;ncFXbf+igGekD}yH^O$MV;O** zO*-yK;7sZWgovAxkR|+CCx{3%d0B>Mh^eckN`Rhwav{r&J11@lk9Hqox0*aozqZ6M66U$ zi6|tL3}aVaqkJnln;^S1$OC=zGf`A{1dgyT-05{*ue224X$_q!8@>+={~O)OdZx(KCdS+@Nbv;{^r~CHYktKn5*YeShBY@tNm6A<61db z2U1_%%V)g3mz~3Y1n|0a)G!zVgcESi`hG@oVc;026K#TntC_M_k(2@vPG~sT9Qo$I zkCa4>z}MESIfi-ELD<7~4nLews!)d4-ZdvOi{7oO#}tdY({<^4wro~qyN-^v%RN0r zA^9%V>FO4r+JsTzXZuanv4ACauNN#Vp1ArB?)mZ>%P-aYjTL>+I|~z|PykXTg~Aj1 zTif3J{}{v2yn$P`-ikuc$xDXQ#Ih(PDB~Hv!QV$FGRw`ELCBNGQI9tZd|8lEGEEHPbuq+?$Sbh?r3=B8`9^F2q#pe_^>rF;ge1f;l2oMZUd|BT8mZ{ob zk>V*w1t&#Qo^!94D>#eT;7RxWxtbuF{0P+0T83^;MM0&SAd$^MSe&k0Aow4Uq5!9X zrX>O@xSU=Rn}oa2>G1@v@_JkcvHd$OV3tJRhdU1B+NYoU9R#A z8s|x>slK&8mJnzcE;#&^fe5q(bs67A^ix`m$T9M;KWD|E*TLMv{9!Gg(eNvt(UK7M z5^bAue@S3gTk&pO96i1}_V~=}sG=_X@M_Lr-by_s_9BlTS$u;dk-8#0m`IhvX;dG| z_{@^ClI-Rq%;2+g0xWMFg-Wps_ZdU5CqP_fB~S`gIwlRD6Va2!>-v`7AFHx2DJS<@ zm;)yPB?pic_p;5kyeTqC2UuXpx4&T9B$lO)qN|JH? zT?UlGCGAOqadtUIXBkY`?9I>IwCjjxk+8I`8>axX;W(*es9}yblHs%uC+M(!&`QeLizKxnYg)y=KTf-y?kNBL$S2ol zrkws1@nrme5b@|Z*cn^>w}?kgUh~r+$&Ui2ofzLTT|`;LPSylhY6>8e0wzpOkCO!! zmafy}WKWUiGVW891k)l2x#6+i1_It?JI3YgB3&-EIc5cG$x}u)|_M?L$@X=2CQN)Z(`&<%N1cNWZO@7GX zVHj2nqf7E(y7Md(m&AjT@ZylLnt3S%*ZeiDz6*byI1wn_2N9pekL5^M>6+|kI zCnEhviANF5E&6B%p-XhcV>SKNG!Jr~=h&q0;Elywlk(>`K_{m$GgyC8ZI3Gck|?M zl|vr)ZzJ}3Dwa`Na1G)qGcb2afbEe>!`nXLz%cdj8ClXDC}ey#SaMJ>)Gb%@DBN0= zZ$0~kRjT-{bTRW*X|xW=iD9ZJL%4d|Uhf^w8JzPiaf3p?y#1)4imb&{i$8KF%YKb@ zsDj!%m#;@&ySzSXiCK8{z8E^g^}3=Ugcsh1X0cxQPgHerFOWWNtvb@GWodxH8E_Idg8 zz+YHYNy_iraFF|&g4l0L!uBW4;RAWf9>r)<jTCeP>*7U>QnfXBN(I ztdKuUyz(mqIB5u)+r|Btmw}WUnOLQ*QW~&LI~}Q8(mbQ>o_iaX4`TB-l#PoKCBhTOJFeD+xaDd~8wAl`Ny z;f_QONY$fpX<~swrQHfx9MYELl3_ss0fdk-krE4Dxi)zFeS^0^%lmIWq&_4epJG$h033CtDga* z2qNqFI(EUdk;+`rP>W3?MR`w4qcG5B2Yp%P{9OsF0YLdn`Jui&mJQ6xkLV^NtXYohp2fv{#PGqR{yUpGX0MhhE|d-NJxz4;&GiW zk_agjyQ(xPRRp9&E8fN8wT+I>;q=Em<|}!5Ik{V`bO7OPF@?Y*_$%Bynn{dBt2pum zxN?@N z@=ra_ z&{@Z2)}~C5i7Bf^)>x-h)Vv?e8OSkE#M2uP;{G9;g%FjL<~g^H+sd@^cq+p7$PYAc z!$APNPtLsxVgX=ES04E^Ht0M8+6^i ze^5fN&6MpHIanMPtAer@*2kt7?*RI!6C%Q#1;0imxB)&o2_|~|R&tJVG+f}v_NL8R zu+zqwu#0tjZ2DN_R@7YK*aP~FlWX&CvSmb}+Q(PJnfe-^Lq8rC!0Dqj7+&9=p@JbM z(Tly84DMHhzn4zgz{x>4#{zK}(~mmOk@*dd{B%LNUbE%_gz--H`~|y1 z{ga}E8!?~2FX&WuTqj>>l@CKg&wl^FvkkQBFQ~+C%CdjaQJNBQ|-9a?cOnOPFI@gd8qVE8 z^$(--kHdY1#C(#KdLNesMtF3$g>3+eAgl(bO!e%by{Ue58x+`W9=W}EJ#x~dAiZ=s z!JFWYQCZ>NP92tx>XRu#4*uteXbmocdj2^YW_^x{D*w!gC~fcTXlCN#@L!e}#owo7 z28EDEK2&XtP2m1?-{)baNg+jT^-B>e(OF)AvSP^P8*tq@uQvD|zX&9!H*sE(Oapt; zH+_8ly8XYT19x^uN0|F(QmVOKL;f~~8dFy2fvoqU(Ng6nB$|Mz(}^QWeCyR3PH0CJ zi?QSOJCCmpUx+>CW2HTF(&V_h(-b6hTq8_OlK5Rc>r<+4nJMU0^kH=M^n0T??Z#so z*CSn3(SIalRPoB}sq05=;>y3cboDCW4(v(t#ibadrOfNJge3XZP!+F6?0a>-jGld9 zUP6a_^~xvS{xUd?yX9EQ5Ag$GcIgq|S@<8KNn3&P{;!{K_!ZzE^A`D^fA@b&$o>rz z*M{*xS4Vv}bWQZcrof~BD)L1bMN~*aOAVS%Qslc77~PnY=g@Rf23y80JpZTL>gI!Q z@Iz!2RFG2y$$9=seQTw6XUG5k=sfTE&AQ*kx2C^(x8K|T{)a#} zQlAS*41oD*175-e&FP({8#Nau4_=4e>Xo)8(zcPbP7JaDxNqBEIK>Zjqds_EzBADh zUe01(TpKYH3=9Hohe`ij&M^@T?xL=d~zr7aU*6%DDP@{+qrpQbL8UNsFFL|TyL zq%2cjWe@p9{w41rxl)g;mG;r!fsDi=?;*ZQ9GXC_mFl9ol8Y}~M86qTqC%dwU?3H>|-*G_oPxCO`Aw(sV@}as?jP#d&)!iYD{E&Lp+%cg> zMkOJmB4hhHN5WL*_oKc)!d#CQ#g0j(5h4n=y3MW)djy@Uq}0vLKAq{*qiN2Sj#uDB zXbkV3*ceRw6Z>)c3vG#krU{Myi%eJEL12O-&6Gz+u5`>&x=yTC@n_5s>|lKt$UtkW zMcXP61rC0xtZ{*w^?>5Xu^7vuflX)X8aZ-#quoNeG~lRdEVc5)WGv3I!}sUp-Q4Hi z*pgkBo^v(P%HeO;oOO}jLZl9Ux!5mf?W88obj0ZSDb=h}1qTBGJ0E{m5L>V@_f2+Q zjr!JTR0lYCu18)(M%`m=+{e5@kuSjVj6za%{t&0$t%M6#aH&OTm>#|re8yz1ecC;4nw(FQfJm5P3*lbv?x^N{PhUxuM zEtIXu%8c=lZy-&XT&`|BKBgd82hT2Vh9RB4ss`qqVlJ`o)OR^$_9X}3NgS0!Jpv;! zPozL*B}v$n<~2r&fXRc^>5`%u4W45&gyy zeSJd3?4Epyzj07HxX6MSvN2Ia#jV8P(FR40#l&LJ_lcQlNF<_}Q9xx>u#xpB%nEoE zOhw)+>Nc!#c0*h{vjcch5re}XfhuN+b?XQAjlwbnHmnPJY@zJ!FOJ0^e9{ya-K-nT zuZATX);v9YdMB~h@lcCR3=8%xWSmY544fv?rLNiohu4W75iC~CZKh{Ul=PNPUAK@q z4z7uO{FNebK5R->3tfg+spenF}>Q=d}qO(xk27OFlDU*j0E1qOA7zDOweq5k6%26l4zM(E!k)e885iL>Eo>80~a4c-GVbD*+LHzUwW1rHnXEb_Y9;Y)Y?fTxO z@^@pzF$OP^J+Qy5ugZ5h^Yn(3Q`` z6=-JBHV(ID#mZ%0=f=YydDOLIiUp0pBG!|sNz>u4uD7WY-ii8Uv9N!J7%!Go%LaJy z%8GfrxigYoz-ZB6mKmdKo(@k;n^mWT;@k38*nwFKdBTx@7z1nn@Tw|5%VGZDsb)sQ z>AhbHXyowNeX%KJi{#{CMJo;X@M24|TZHhw9unO8&okb28t$Us-3nA;vyfcqD|2G8tMW`-?Z|KPeIAo_mimN#&p zA%e1j!m0<;QzR2I4Mb)U0MBvFf9gwDm-2AgJo^Zh-j3DeHP2wlt31o(1a0+T^vexh z;ZHEh00sQ?HZo9fujPzN1Kdw*LZQt2q@X=wmJd(nhB?E!At`=JK41a#?Yp?e4xND# zgygoZM2NE%4Y9z$9`f|C=hJZRjC&xQBalI%KIaXq(RP=NpO32x4V)6QHJ7d z1!--Cp)qUCwjiw~Nl7YQY6RYFs;xa?Rc7vwwQU^Nje6Gxk>(Ut0u)ZoB~b%%FqohZ zz#cGJXhs1TEO=|dI1Uz$@@cgw8V+U5Ga3$QBy>{Oc9qnwnGMaLHNzbd{J-vIo?f&Q zY*J;6{0bi)0fY?%h;vXcJ)3E?W&XHAUybf$wuORiTry^e9!`07^c^Bdw$jork5{YH zBitXHgN>U*y4%+B%|=36Kzi8rc!MTXn2o;$h6>Dur#zDpDlEodZ=>@c4;J2)3uKr0 z_lGasnfQ2A`DG(n9J2aq70+C6+rC8$WEW;nsXONAtoT4y-r*23D5?HBhV%943X1+^ z>k6Bb$9NCy{>Bihk_|rFz0hdm-`5FI$iPtk6fOcTrq^XDpVXL?gVvY z5_KqtPCOeoSM+>avfjE7_PR9gC6nt8^=ic1uTafHwl0OzU3wnyi}{SlfN4}Qi)d6H z$(TIn;cb_kbdkT&87_fZLReA7E(uzqSa3-UDAXNl*$Qcq(T7eTY<*(;BHCenmy~50 z&FCL4u^u@!7`5}RI|v;HUGkg}4~G(0#2aEb8*<=Bm^6j*Y&jgN$@axG9kJF&ZaNa~ zvym>8)y18b{2THXv-~d18?sAtzE$111VvDmP7Oynvo)qw}Lf$sHv7i0sSYTa! zyRB-8y|?l{;y#01-Fy=vn7mj$dF(#l-+n&5`{r`(OXkpIw;YA=8m1LqU642W;xMG4 z%u##l|L@QwZJwp(pMUuaeQG!VA$zd@nY~3VUF~h0|66Ay`@gdxY786Di(S!Bne42r z;FhJ)hRH)H5Us2^AyL?gBc=10&`h;K=xYtM)Pa4ekltaCgLS~cAOtfY0XRHUT^=~D z+bf!u5|<{6bQs9u6m%8iO7OsU{xsdL+2Q<9>F`x<2LlF1PKqlql8XiP*)dWuC&nak zp_EK++X^L(d8!@zt2RudM;P2EfVoY316Bh&3Ny+&^y$xjeE=9JzvU4nGi1zwA7THT zG~H~(7pM=1X{^3Ab>wR5C4+~*v9AK#d?HK*Xz zWYo7zBAX!63XIxrPBzcVQ7Qa^8`rZ>U2~)aZ^j7yT{+b$G{|6j$tL!>Mt{7*x`P+$ z+ZcmajzNtM!#?iOs4l7QwJGndCd@KX&|Fjo5OCp!1}t1OLf&|;F-bou5$!7FHCwoO zdS_SUq~W{`+ax*e34r{%gpH}v%|Vp3kA~`H5=6Y@O()_!#kk!uEO}(=J$QxhtC+?d z0RgWFu{k|(9YJ}qT`Cr)tY;jU}e=vDI5ajP5trkf)xV102z z+}Yo=vTifa9;vixFldQyq+vpv-8U&e{@`)bU^cy(`Q&*P7M-PRS7xnh18+CNrrYY- zo&1Mcv!oVVV-@bpSE6}k;+8r!B{(*}=73|9mSLI0(DKyg(5Kq zeh9UocH)_@8jf}DQq7hsHHHJ_1Nv{$T>i2JGPjk;Goo*)g8$d{$oJS*lhfT^f687H zNn^ZD_n6&>80P14Lsmv>*f+IbONVH^{dtf4(-DG3Vy_83CVm63a|l-!fF1nh9Yzn? zSBwjkH=)-lsBQHKKtF(>A3Ml6=CRQud7N;Fmn-}xqEA4p+qF(+w#jIB9kRhh-~mt_ z=5r3(8Sn^tBqMQWrXV6GntB&|W+dZ&fSQL<%AC^}EQt)$K`=SP<-h~rna1sqoW*v= zzTCqSPL559uZLaVG6d{h`zOgB|O`tC5Jq8NOb7t$80$ z)Ssn!9GTiny}zzkPDi%-XU8S2&j#_B(n@1n~K8O9vdPZOje6CnDb& z=DL7}FmdpS$KQPpZBvd+Vp~107QpxSZrB9k`~gn<^To;iyKtcJd##ybN<;9>gI7Jg zbGI2@l4kP#a%yKr-=Vrpw+9f|K+^?uKy39rP$qrFZvPvmNuUBtGn=E(;tGv0BD z)Eg>Vyv{m|8MYg$L?v&Y(MI|I=MP?rCXs`jt8X6+SQm5U=o7K!{WJw2@~!-`}Y zcWg|r>Q*~jcFpP*u)$pZ_(H~j-kXR|qp%vpAOZbbp(z}lm$}lPsM2xBoU++ot&DHq ze2?R}&%4 zs~u?+naXy(OPOHUuGq|XN|H7mSbE5x8e*0xmT-sjc5`l47;{d%-km?( z+|4sGQrV8dBNYX%cEInXeGh|?z$h?$FQ>jEv(H)XMB~W+g8G0A%HdsD)#2ojXI{zh zK5u{US>Js6(dm5AUz+=s3tm$aJZI5SZG_py@-TT9gfKID6%v-jqmVBv+WJXQwEby? zU||iyoEg9SYyEwg8^3#W%qlm|FI)4fD+)^uo{4F?j`y#Zc#>utJHuq6F5Rkva$Gp& zB;HiW(%5%CdtNukAmYV!mLcQ|5L{6H=gp$Pzk-jZi;s{#fg;73-T-GOhyE|zxCfK{ z3w)NsO@IY{FG*G3-85Gq{v;DX`_np2G4iD+PyQ);KULoU`mmn%Kz)f8L#!Wha;|(# z8pk706Kp%ftzCtsxRqcj1CyZqHK8S;Wsns7%)0_2|5cq=g;~#j`qR&0BDsD4s=n_w zR8nB_XjC|BW%I|(jd8qgO`EDhK5LepcGlP6omOcwibuB3O76ph=Nm}Y*fAkDAp6CL z>NahOd|A+Jv^ec(Sq%bgV>FIqgyC%dxTa$!*V62;mjLxmD4ehXugyCU79)(2bK%a4ih}mf!Mx18XM%C;6n*9UHi@YJ9zx!?e2c8E z%R^Nn38anYq7{WiY0^UG`VW&jT{5a=;fo?Q8u$7nQ_|Idk-992u#q_cb|VssB*M`j z2YKq72-l&7E440zT*;kpHL}_?Xw~I=e81vMWn`0-oWXV7Y}Je}gk_JMrHYymT@iIv zo40r9P^&o?B1c8!E8XWDaV4xpd7fYhB8lC^vIZI24QiE>wac!!hoouMty~FQTa|Ma zPM1BQaKmw%aA!#k%NMh@$M)x@iNz&5q2!;yvQil9Ri9wx$CsE=9A>M1qO-5@pHnWF zt6l?S$KwH-enEw=F*f6$GtU!-18px*;|c$Q#y{jzO({BQ&l@Q-&p5HDdl@Qr@sAj* z4s;tuSKQmJf^m9*}#XYz?|quQg1Fd4Kv#;*Hi}Z93In zW~d)ki3#JBDu@~Z3FT>%F4t?({Y9@7r{ddc&;P-ddoAUW()yf;u0JOt<9~P}`agYB z3Fz!>W^ZBU^ndSLs_2^N@8?~a_BzC3&=G(j35&j2cw_?;kJxk<05goLmb7*vFaJ_L zu*Cb+UPr81cIAA0yOrwbHP^#HTX%KmOY)KO*3|Iyb*0C&wjo#UxV~B2w~0Qu(J=`p2tsJEAWJ# zI}rc$z0cQ>i+p>o%bq9hvcZg7?4UV&UjyFX#`-x7v~V~6X@mn_Sl8Vw9)#t|j+_J3 ztS}ROp6Zy6yR;lNRIDu>S@Or>f2&VBzY;1oiRq+I#A)3tXo`R(4y zFIxo@e;eRUjuP^m@H;?PH_d~cE-?rjGQ>cJBkRsZf|JSNjy}wUo)T zzZUG5wx!9;s=c$^#i`YxY+mH~QR1kldpndr#x9ss6r$6SsI6``r_D&QL-R6!CO;27rWQP2n=f{3Jp; z8p_Y@Dd#!do1^52is%X+wWgdP8k717MM!#$OO4_qauI^3W|$Z3(*3Qk^pIri61(Fh zIv0gO*a=uhx>|Ei?1q)3^7|e+H&UE(=f_pfG6Cwt>?Ybtj9?JSFoBN3E&tc;W?J{1 z(|5z#aDuR|y`Lk+qIcvvzcmll3{8Z5gRK&sj|qu0v@g$j{_MaHgV0M)zRD-X{A%n+oR-i;xb$n}>KV## zTvWeJdxc;9USe$>31N%Sd z$^W$ptX7*+KvVvFmnWORivt4G#~rHGW!IRJkqeBpwAigwBEgP+LjF;xHM8YawXkPC z*L%dVUvK*@RtV|`e9|Ma@D`xRT(6|4$EzMsk9 z#;1PcfVly)|dWd<$YvG`)x+f9KtI-1Y8@XtPcSjT$so~nR;U(J~G#__E81z zF8``qqv3U8OwJVJxP+mcOj}!9#l*++_dJ_Es--**zIz|gZKq?v4lxhkRhR*vL@B(; z+901u8oJ|NCvt=v!^mS9(qnQwDo1KQO$3}Kk?xt4=8^zG&aOfTvsTNa1PZUJ7b$ED zBEKPzsch56Akf<3SC35IdC=rU`3||P$_#6Ao*J*_WPN_nW1i1A@U!H}K1==|^0N51l9#h`{_i+hwJH05 zQDzt2c826tSCK6(;qoD*lFIBWRD`3whyu{5)e2&rwv{-h6En%&>Nv&Mxh`?^+8iNa zAa-Vo^B^I^3!A!UP7@8 z7Mn#8XXfc^>&yDdYA1_h_c?{=Yt2c!Q*^!-pD!PUNx66cdoL-V1gD0wMKZVrIPUN^{Wc)(qbM_T&U>2pV{R1pPnV#Yx^le__u_m zm8zw*>D0cyvZ|(~)I|3mXpDo`+RBOfg0OgVs9%W}$5QzYVX;?|Ium)jC4B%0!y#iv zXA;{;`s_vRSFP<;H8i0R_9e*SRt4z;s50lrFZJVMDl|+nX-v|nA-7Ui_!|oX0>TX{&k%Nl zquAjm%)b0Nu@)v5Oj)cASHBS&vswRQ^@#YRSzP$PQTgY2@bBd2+a4yRFD+1gr#o6u z{#W7iZ5!l$7XH2>JBHqnt(rU}w_a35xltV34;CTND#||0;net)Owi)`=r^_RDiC5JDmbtIw#Au-StB;Hc<@YM)R|W^(J3CIniOl9Hc#zdyPb!VF1AxVLOAe{*}dJG zhdsYDwK_7a>{P=;bs3)dH(ThBYR3^2Q_s934Rz2sZDr}W>_iQ^_?%;kNVnda-wrcvh!w!b0O1ck^8$rOer zYP4`VaT|>5{LWP8jK)@%cRdjLJzvQl_N1^;5U1Yin(!bqsFtX2pB8d5;rqg{G@1;SykaJMYoFN(vPC1__5c z&%8dE81ll**T*v0_`!w@4`M_p9+*mOQ02OU+RarUbUj7#>|O(7opfbUYBCsEUqPMv zQK;7_fgnxRd?R|%*#b;uu|DPwUNtk%qylxXz><70gt#|LLS=cw>uxOG$G4 zGpIQk0F}&7z_C4B=wHk^thlz^V6lnG?=vg3Izza8oi)Q3>(j+dG$y0|wExb@n1S{o zq6iRp4(B(!Wq*#0Z-!?I5H5gE0~Me7$gCpI<*)P`>Ai={^4|K3AxRgS7$WERUWDIV zK1Y&xh5b3iB`a|7UC&5$z+Kv{A=w_m8DM_~6X29HL|*bGON|J2BD4!PB*(G*JIyf7 zKgaTjQ3z$yw%xgLdo}`!JR~zCnUlq!yhNFyBgj{gH(@yCH(t=vBYgjl@XW8hQ{;J{ zmz%K~qk#V-a$Lh#b4?BKu`$nKh1sHltprd&X;t|?tL!=(CADN#1gTG( zbcEutpvAgcB&$L}I6Si@xUjqYNp^?2Wc75rUq`2dIuTaTe;-Zy`}TJ5{dI@T$nPT))Y84kBvKST;6vB%d z1&>zpnPLlEX^;=@^jj%cUwy5&>wt$NU%PEi-D-Q~HN25~=yPcfo;0B7bZ0C~QRK=x z0LB4-wPu>v+ngn*SpI3C_m2fqv9}H)GjO>kZOcR^xAIhH9%*=1ODBtsF?%?Ncc%8m zM*=^*C;k^}@7SJc6lLpHY}>YNqhi~(ZQC}gV%tvMq*AeMJ9&eOanjemy3g+Zy89nI z&xbYVnq!T557Ul-$Tz+A-Zty!gpK9^RF2T9jWDd7&3ieO=QcBLhN+GI-a9GZ%Z{n8 zZyJB?^4bp7z(voMDyc^G)?(OEh^eZH_}yby=T?ruC`l=uwmv71Y`$tmZM;o77py|{ zmD{C{!paF_nQ$wcj(x;PY}E*V`2p^6!YSAS%v0wE^9SQ~bdJy=l%B0i_iy#@s9?Mj zcD>uqM#JN)Ur?xm89*2@77i|PX-oh)ei_Pi2&L^EF!4} z@0rq>zp9_nb7>`=(~mpWEfdt^U=03N$x>HRo5qrS?5v1|HPr62`PJA@Jz7^UAvj7b_rc*PBoo99X{dOnV#4gH{C6h75kkkCi(Nn%fk-X~ydn3*}L!dIhg4s{!EVs0? zz)U`;OJSRmSLrf3XYDOiuFbKu)-U*_Z8K5QTwAV;cLPeJ<+VifQ3J*ml*9OT{KveRioB{W735;H~-QetaOaNld;~)UOvUR zOB2g3v4B2w(?y*FKZH;yITL>^1*%`8noS(P+St}dS&4YxrMsxRfWPC+;Ng!6DDtl*FUZR5#n!qK@KW<4)#8?Z6t?K#Y)a#z)k&g%!` z?~-5eLxeWLDh;8q=|dZgL&mGGUr{s6Y7nWmizL!9~>%yeg1tzV6~u2q=|RFq0T+Yn8%PJLd5)ZhVI z@Rc{BuK>v8+bof4;Mo{Mmz!s&7&Dg#Y@|Es(Hdhw(~ttGS}pF@sm=U^1iDk)jQdSu z*mX0A%O;E<&c%nz)T4Axp26O_FR61fY5nc z_q=P7g-?6<;^B$~ejii-8H+qV;Ca|xCP!I^VP2+(4J-NXa=*GCoWyaDqN z{&4IMN)+VT4PzJ@1`T(KsGNu{;r|qJ zj4+40LB8)UZU1{4djD0K{_lHzt@_4)NIClD!sTpnO0mD9G!Io6S-r7dOHJ9^eg=8vwiz1@d=va?>vpBhZKVsqQv1K}d*r~iJ4y2kQW z_k!;_;~vtbciF*0Pn*zj7y~|8SPeXjqdGj&1(faz5dlh7Y?csP->amlr7hPP! zCF*@z*syVQc5=>nN~L_es8{sh6H~N*f=fozw)6K9VD|x`0ju>OC2{HDdI?yVTPka{ z+%GNGhy+(ZoXyh5;Z1)El)XBPG!I9Zg=d>VZPG;%wZrw*~=E@v9SoRQZ9oD@#8 z!a=>@a|pM&&Bz--tkP~Ipw3!y2D656z>Cir{mv;gbb?&J;Mhal(J2pRsj1&0%(KWaZ-%BfC9Ij;244>;%5`SK@k%tL;-| zrBmHTz=yfA{?@emM2m_3n3z)}A!`-_Y6b>`gSxGBOQ@uqHHGCdAu~M}?_Gbz8Q7tM ztVUn5cw(P*AibOAg;OV&dOI|->HleTjcd`g_z1W;GpAQ^Q~`ZZpr{1paf{-4ed z-dTy1J@)BEq<&&Ywy{a6qO;8xPb)&{mPK>+y58VBeEWJ7GFhLc$eR5{KR+Ts{_&}tBTZHc0c;{{aW0mmYVj-quxzJ;JXMA^C(^d0{7PH`U>uQ%fK+=kN%-QU5&sPBmi+Zl726g~eqYZ}5u4CLA_X z>l+H~;Mw{3ANpyU9^%o(_e`Dnee4YXmq&*GbL=$Ct*lM|GvuyST~_fwgj5Gz-bt;J zqM~0>ur{)AVi*!NNT4RHjYY|2(Om-@XQlsf{EkCBOpE5i`7&Rb7Q=C|K7RzJ-ELZw z4eu6JG9DL<=J^ut@K8OC&N%LXOzuX25F9|l$35-G1vhh-C#W&a^HL_UB#o3r&>)mW zSVugokGdbaM_AG7n?y1AU<}S0I_Wj`s58O!|DE8NhezknU6I-JOxx7>bJ&H(48L=j zqU$h=-1hM9%dw3fAYH@P)+DV}NB2I0iv%jtmI(WeSPq?RXXuXUYIHTjfv4zZq-b8XQI0Y%RmN86J2IaJw;yd3k^4bf zB-3{qVz8#YX^^*b-2f$_J0tGlWh)(6CXdwX$!03P;I`gOm^Fq#9eAqtMjtuz)^|7f zgTY_1AGea@zm~&sv1-uVjc+EbK2*TD!JIb z`PwlbnJ>JQYZzl0qG;Q5YkT6iME$HgtuTm~H?Q0D`3z`wF1C2c;5+SOiLqy<6c%E7 zuY3$W%~x<9eIHh3GM!Skp~2Fq1aOqa7gbVP3dvKc$=2C!A(9h^#b*^Q^=ST`NTC*5 z;q3lEL^0=%8+<(SEV=r&aNtBy#?M6cj$$_!&bd->qT@xiyMGk^qPczktNCCd7{*gU z9D3gL3HtVs$z9PuRPl+6^C6Gz7V$|itc?GgsZ6v5K<5zUMt>OL9EYm0>AYWr4ddS| zr(!O!KJAiVRiaP2(LFqvF?fS55Vl$gTtAx)h;sqCWf@|L1sS>vW0ieGEz&;RKQEm! zaR@lY`tKL-1CZ!ngWv5<@q0Aa{a-$3s%|dsrf%*o|G7J=G3B};j{a5KZ$?8ajUa8i zE(!yZSJJqTn#0Rz-H;j-bs=mzA1tdi5mUXI5l0S{0!9_V2B>uUt!k7N3# zu(mPyaCv07vLCfqo2ojpP50Ysm+*W6pcj~W@ zAkxIE6Tzh_@vQ|=ZtXa|wAFi;$uh4yK#>)v-yN~mW8_&(SZ^%l)hRx<2a7b)_08BK zOcdXjCA4-+wY8*P%@(VA@j**su>q2|$xCz2ny zju6o)Kv4CNFn)lH%`Co|OOb-;%_Qp~)M$~F12|)iPSLOF2Tr*gpnlyxIV!yK!Xv{D zs{jTBeYMsg?MwN-L{Ew6=mb30D-4B1N(zaw{0K)Hc}=w!M7@fk8g7DexmaECw|w@c z(g9C4#8NwWmD6Uh1_S#nbcIqC26edj&Eqn*p1qv^(J|J`;p*t$-LpdKIjS;37D)r2 zp+9k!>ZtUkvgd)=yS`9TNEz$3+=nyCcHY7aqMBNk0G51GkVWwtIYXmTulHLM#fxr`5#CB{G)90r@?{7lm$`9jwFXRh{-3FjlGU$&NH2AT07TTS`j(3{*J4>x3 zp;6i~i5J<;q<+xM{s@M^Q2!U*9;Tg3w`sZuu{?#69O2k(^U+ zei7w^$m%7)(g#32MvW^b1doaUu7hff5#0%GIQ$m<_8@8tU=5?#EW|>#mo0?c8>#x0 zLX%6yvL6fW^8F`ZuXy?pDzV85#-NDpNCWDcVuz3fe_L* z%|mJph}dB*(|Ijs5YeKq-N&ws;w$~mZWExqADldT9Hn5;OfhASRbID-bVD>}%Eb2d z^flMc7Y5rLI-MSOjw8+mm3DnWJQuQ$MaN`n+bK6YLW)?402_Z ze?)c&gI}@5+K}6e>JBihn@Z1=sW*MvuJ+p)U`T~D9FRfMW%gY}CYkf7FM$FMYMuI= z%l<1(6KjW*p?R({A;0^DJC-DCsW%Y}YEsM^zQIpjWBPQf?O{#*_TKPfPaQM&ZJJnR zH^{&AFexAz95;rh)H_dLx>}T(^K25TrSojr$36o+A0+W0rcRf#kQD+_l?V#OXZc8lJcwG`TZWd|-5z6K4uTsj2fn;k2LsHyX)5C zziAOVV0HRaa?l-t%Sly?=@t7Sa0VZ8jFv`gwjoM4xDEtCo8G!3N;#r6HBc)excJFW zYZHd(Rvay=$k&cY8XThGJ&+t;V3R%kM81^G)fL`zeM#GrgKt4vQW;eFkv$r_Y@?~Y zGOc3O9$4jB!^93&C@+{nh1^12WsMsu@~X5GGy6-9c#KBph-41x;XKmF=bWL0E2@Vy zSo{ZaP@QZcv25XQX+vi5CN}vW3Z~%DnwHK9i!6DgRb(udLrMcIab|+ zPD#?h-1>zR3vls-glm#~aCF?n|6!2La}Af?kfd*`-R0V#nqpJM7`cPo&L&CA&C-gx z{)!%f5ji99aiV!wOdcVIg%PPH%ut6NWv`Pk{hvGG%DIBPeBWZ0#?&Ut50m9&4g;A@TMf6cMw{EAD$i8{T!>^&*?c0iuw?eJJWt@IKFLNbHv0w%DR zoCu4Rzh`Dve>a5m4kNj45NZ$2ut@pNhN;r+E;FcH8jplqaPj?v?4q zZ-1L@DK}IYNe{A$bvFnsZ0NHv#Ab#8W;5HvGZ}N+nDP7eO7-_Hp{aUPwI|?f87$^q zq4?TIuCc|;He2K!LrAhNwT+?WHDf}4lPRj)x4MXMPxKg}P!-f;Z|dwN(5$>oCbe64 z!Rxba9()T?uz+fAsIu9Jf@b?YIo(Zn2nNl2$zH z*|YGW3`6)Y>t1C<0_~^Plz;GJ3uRn@L+ynq<9$0??DY;~=#{H!cmyR2MauigTm3uy z1;+UNMV^EfophT<=afAeRrgUX`1~pG%1zRJ<9OX`lwe4psQ^;NlY>j3gWhikrxc+kMEA>#H_oM7hdtc%Fr$`g_d0|J*XLwpyr13wT zGWG~>h9Gr@Fn0!c)!2bKbU*3$diJd+*JM9!ikodoR9Fk_c=h$+|t<8`~T<0)M{MlE?A&{Nyw;*;J>jqLKqX&`?qO^oG%-dId~zSJ7@(j8IX-U9nnw^a>C3od(tD! z>P_iI62|yP1BV4ol#7gA5?%B(I*BP1#g*iN^A~t3$`LZTq*h#mSQJ~nx1=5{$slwj z3I-u#qz?~AdI}G8lYv_6$mM>|w1}K;#x=QotI8Z5zNGmSqip*89$99|M4Kt*L&%;C z+mcFjkdD%c{#J6_T@MXHbzM$NEyNay21Vgts@FTTw_+r_Cs*i#lt`CK7?*s0o@^Wn z$I+wPLo31bv9e|!UPH;YvgXQ0Ki*=qNY*iQsDO7hPJsetZg%Rm=rJ=7myiyS%*i_~ zV(;Vc-Qy*Kt$FHL1*Xd;fpQ&*O5x-wTuo|PYpvwsYH=EBL0%4W#j?L`ejcvP`btx@ zbS7oRuC5GFDIUR1b}0z5GinoTU8(Apa{Iu7iCb;N7esFbeI<%ibzx@$0PUlvgAFpu z+OnFfj63}C1`@GRrFnjSt+T>EY-V}@!J(5|{^~s5wblvx#k)lDP{bg$PL;0vUvtk< zG;QRVEzp#^hK)?b$zkeKRlPjAMU7#2v%iOLGq>p{+&k{`m%&AyJvDHoWBftaU)G!=&vNDRKB+1QanZ)!_hq^jpkr z%v;2H{<;`1ted&kLKgelv=xRGCoJzCCKDn-xfFwi-MZ#Jz*I zD-FG$`9up_u^zwY(T9H;m%#W<<|PFa4tx2L7G=I%o1Yi5%9&{8;l!}f4>o|ay)2#= z0H5OkeFzF*_N-Ga3?F+a*oD~(9GSeV&tK!?d%NS^`?W`({}><7@&7vC`*=>``Kd2F z$WY)WF6=t!CUl+Sma&&jH&>eLavbO%)PDEhn3L*nLjAQ??wQVX*HM&q7hSrwt#tzL zg$%~l@37Kvoi>*&iIe{rr;saG4Fr(4OpFycinnNL#E$}UzKP`b9|pHaZw(^{u*t%goaZ+r1BdN3DMTgpTB$?I`1jM+ zjdPjW+>yNF2v)J~ty`kZ%lB~48_@qYMZolv`H;_@USIulQ4}?(Hkz%(QEEF**Br}S zn}SO+$pBgz?%0p)s)zpIRPR|7A@n(~t24Vqi0v(;o3A;Y4FeGynhyWq)Ud4mI#?H= z_tfK-!8?g7n|BQRNt0ru++|mN&=j{s7ZAb(mfHqUNhfNq2yK6UpcWWdaQN0(hIro6 z?>g)7Pb&n#)DmtT&&`BqG)xqG`aaz6?V=iJwas7O8o;NjxMjCf;lIXrpsQ$&DWh+s z`l85 zp%)%wyZ8~b1BPQtIQc7eSE2p_?eteCe-Q0!2*NYu&Vg==lBX>~7DYDczxHRO|6b0i zjNgKjzU@dBDE}+uN=+AICns|=abq`QNo%kFvLb1osp3nZfBkFfZXONGL)Ij}71l>= zCW&SN0aZ>p&4G~9x`m9~0-?N2&t4<6iYxOu7zU=#Ydy?XlLu?vRa3DpSm6xM+AG`{9f0{sw)0uaW20?aaF z57CyemxwX5pp(utM4*gWjOCLV>m?|6PFnqqXhh_B`5UP`p#0Ln!EJ08Mn@zu<|PNX zWwvn=B_vn?21P(|@RK9A$dkDa@EWg!YLctG*wN<-nH)x#S_3#D$hV@e4%8Z3V4t^8 zCMq{*8#Gz?in~3C;t6IpvRks-Hdl?D-O@snIbrLpM{DdziW5AKT}S0|$t{0*|MDIk z*t1vB$W3qF^ayry>m0(AFxa8my_zhS4_<5sX9hA$IfH}R@n{MG_i#W(Sv?L>@ZNiDk?=?OBM;z_uUvp8#`27vSjbI%-7xMH{_m_bJAyEqB`7Y=3wY6+z10e81zL+8@!b(M5qi~ zR4oeQlxI0EjThAKmHyy!s+dZb@~36Ba(8UbPC*xco_AV{@2k-+eXu>WnKiZMpJ@K; zlC)`=psq0OfwYpW=g4E*ERv@wUr%9(Ci}xemXYk@1DTjb)86V|+VnfjWG*cWvbt1e z8~NFTo##bIKB zu+2UPv9P90uTV2A6Esw$>a&F4GLWLKd;b*EF2x7Fo(W|*s$Q|+%t5%|3{kgu%dK$k z1*&M{B{RC`74d5*ZD^N3Qr7l@%F{AuI?Y*`c z*4}3i%N5`mzjKK+^LNNs3AJ2$uD_tn z(pv_$?Iu(vZOKP!A7N|Ez^uC29c7~c&NvmB5x4VjY0r-Qn|+DR=R7~=O5NuvxVEit z>@v6K%DRx=hEV@~MrIIcH}F5Rv_uyghZIK|D)mGKbJ!j(O*(QgeQ6%xUK>oTiMXga z>21w=5f((iRajZ^BHd_`dm|q;tJoKcC$)P~6o?CGE^Qv5uMmRr*PM+trv{=@c&#Wq`E?HyZyW# zu-**IoDJ1Pe*_%HqV93pMHbHJ1oRjn$&)f{EF|W41TX(xW4zQ@ek>06!?0N%&(6$2 zEJC0*lo5*$sD2h`D@rxq3di|fG~-1pVHYSp|+zLDd; zk)2ckHL#r)hGkPukN*v zP#8^-4iJmbO13MXZ$!~XAxYQ7ZOCX?_~U9nf63uouHg+zCOFsGa#Ow!{?BN|r`|M7 zI`SVso`Pk&WFlYoFm75$>75hjO84l`<~ z$(@pKGHd<@^0E8gY+2siT|y{VdW_WZ`~LLzC{!%G(k|G)nauC@v`i%i>IvO^eF4Yv zeEZm3%kp_#%Pu3!x$1p?{GjZ7#qnaP&Jc-*KmPlRGc^Rvj9C-XowXu!kUx~8;f2t{ zi1M&e@|#v7j(FD)iqI2Aux}jclQk2h=aD6MohgzkhnXbO9GMMiYg`Kn|BXLov`Weg zXRXtRB*Afm#^fZ9l`xw$ zTcSZ1qFcUU1EO23fe%8LWK}<;7X8v;@EYaPU{C|5O{ak)q!z<2-{=COTe0B{!dF=1 zP-Ku0_0o8d5am*NkPyu-^b$BKa0xS5fPP5>R&;5deTReOtI==*uQgeKdFegK3H!)3 zXn=evF=%ktkcq&Z(YtS4kL$$mD*@|01u)>+C5P!V9-v9-vmUTc=`$a|p`F_xd`tkb zY?dc{tOGe|l1KHM0c>;af~N1^5IzQjV2#-k;W|Zw3f(m%B6R456k-z!S4R3< z3~;C{pFrwSoe9BfF`i*TZW5mfA#_O3Ga+g zy@wD|0!j{IK?fx5Lcs+@?MA|0qrEc^euQwr5F+`DJkNy?kv%tt5K%qfh7=M% zM~4)WKaYhJl0H|46jDB)g?xWuc1R(`^IAwD*>h(|A=UFsh#~QFc*vIoFc!RD3n&ZT zuLhg|@7Dv;f%mHbtHJwqfVSZM8o&$iegoi9$d@`054>L)mWqz&HN)0HnYH0MP?561gXRuK|Yv z?!}aaErPjXljun^!ZhE4m@qm+f|vJw?|5E`d^UlZoT83*UTx*fP%ir{*5$gRbk%4T z{<+vW?30EDH{^Fx|5BXF@_Sm;dQxB|js$i_h(_4K;PbqW_LP%j=lFWp&{gAg_~J;h zez2G3qBwRIs z4i{e+71io>PY-&Jpb5paJV^EXo<`X3%A;2I@O5bgvuHu+Uh(RAIG@&tv%b9IkE-?#!)a!(q%e$Ys zp#ej#D!_<&o-NyoFi)l?dQ@w!TuX3M`z^lKG?T80EId2J@j8X8j6186=9(!Y#J}E2 z>&eYlW;OVgF6Zx4Qz{ZFbJ}G>=r_uV-uJW<-7CC2(p{cXF7s{|!r47Vt*v}@5iL!f zzWOpB#MJ`_H6>4su9HI)?{yZB-MSjuNg zxx1-+?(~w$%G&#-v}LlmTG-s%6hs~kc8Bt5SlIk%DDhit6-b zRZRB61g<{RtVXAw&&Puqud=qPrciHL4XAOy zeVw;V;E3NCBsK_?#HnuUZ2w=wc?_fonW~R`^n4ooJVTtRHx<*T&(QEhsf0gj@=c4s zh3I)93V7o`m1RR=j-oySS1^CpU$u4Urb*tI!Q4dAljo|<%fT@4YwS~hsPV8^Ox`ce z+|u}qL3=uOjYO1y>yV5!$;+Es{vAJ_uB3fZ&zRtyth0JhSFD%FYW^ql{^?ewFg(eb zsZ$DV)75%SCP%ZV)4;rm&P1|P$~KSTKq<@a{%|8f+A&T#Rh9>V{6Rp)M8ThQj+g=VGf6-6cfTQI;@g-_;)V>`n1a%s`1Ei^D#6q$ zA2#Bja*|6`trx?Mx;X@BZ54A|tJ4q{91kvc2r=@$79~7Ff^u4?Z8?NB~AVX3Cm%4NIluuVS>lj4ypIH3v^2 zvp=Nzb3tpw2=ldHfS4~Vj>Na(T8kc$F66{H`i#KprU7s@DiWFd>FE~lVZW?J@a?&pO|DOWf53!g1jc7ggX#TIl7a~5j%c=b}%kmc@I znUs8NSv5BDJ|ngtdnF%%4MHga`Iks~QvRq?8e9ziDfA)BWfIZ<<}ix-e#c92K_$*V zD7qt5ls@+GUCwye30zv;$@x^UbdvWdc_IYf$sm2aU>JOS z&Vx2>qw0*bOjWg}vl#*>$$RV9W%6w+{2o|guVkv^10;-nN-R>bUq6o(YO+bf8&Mx=o1gM1Co@#>FP=3ahm%V_2uwmk{ z1n{$Th8O$VHKD;!{spH9*Hr~vQ^7=EqM1K}eOlR;Kh_ZG7PXpiY0GF7{Yh2n*rFKC zkV_gA$GI$%xK2)SYm(uO_JH+;5`7Ga@O&P7;W(!cbdglbi6H4+amlMG&WtxU?X|eHL`M+vj8T!ZEzv|9N*I;Wq{#db*=}PGxs&|M|Q3oo4fL4N{$IV-30=fdfp4)*_ggk0>hJ*OEok8G2z;@{?Mk{IZAG5 zN}4njJys( z63vPfT5L)H8C?-+DpZdFXG(k#J1o<`)J^&~zC%L`UY_yy*vYPGqh|Eg(TMesU=OxS zGsakYg+CJV3sv!3co=&Y-a*%n=?bcC5$=D*KKgi(<5VjR@U+nzuc5v*8q-Y|&{-7M*;HZg{9AYCQ;W6V>xpKS$X1a4^ zEA*Y$Y3Z_~o;7p<97gkkaAJn@3#t&>ctKD3l%w*!>iR2bvhX9jIL~FuP4nsSeD%&l zNap)6FH8W}p=Pposvs%?Un)NxQBU8EdgL#1x|A9Ka+p{N^lcG;>vTmSP@~7XZ9H<8 zj2NBImyqGPpuhrb6-}thLO|^kO2iu@rX)of6!eP3T--b~G;6jhdqPrp9XyZYj226x z>2F?Mxp!O~yw@1*z||L3{5VeHN{Xcns!07)SK})B$#^KwKg0Ya{_PzZ9$18}yIr@c zA-q!E%pd0jOSSMgLs?TV+rS5mdOWZ)U4$wXUei+78&*rwxRYtqzwuT$vJP>Iy-1hv zON9)v*lyceEw;(wau(C!K2F@H<&kGF8$n1@d;3Q>5a%<<_vU3xOmjiIE@+2zIX>Pw zmKNb>X^hciUPG0uy3NQwh<%k9cwRG|ls5l3nF`7bq}c@@iVsmk!dNMG(cS8SMHZ?<9DJrWw{*iS6*EE!n7Z)(ZOI{aks zg`8WvD|P?-5a|O|@*VE+;i*GcEhH*e9q>UTiiUJEZ_}$n=#_#p0eYHqHQs-n9td)QDD7A+a#aS+L54M zf5c-6%TI+WP5+&=c8(;U*ybVa*<~U^TLA-#%PH>uc`_)cY&3QJu+a1U9K<*Hzmis*7ZYG%%GRNzEdJa=^HhMf{SYZqNtP(TwM_P#5)eCV6P{PoXg$9!4mM)wfE z(t^rua-~eewmyH@qWRtB{LN(iZPKc(o>z}xIbFgesRryFhh6iqkiTHH7peYTz!)zg(z+b$?XE*RCC#YC2WU*|AHd4q<@=@T z-h5OKj5CLJNnjQ6-J$%yG%@mfbEre>3d#yYo3g`T%h=cXl;bi=iuj^wO8xni2m5Bk zpB!dJHkAIU*=VYUIyQ>L&Lm_hWn^R)g~#2xN9wR36PKZ$o^o5D9lA^LvP8b8e4(|= z_Cd_~-MKYEfyrmGQmiKH{$btH`Xo36cPYbI4Gz*hHZhzVo+3E0SH3^C$-CEkwe(TV za>lxeli33cw1$xO^6wBw2vjr4_=!)#sFFI8T}Bs2!fYGeYm?ScqAO%^Xh@w)lTjKS z&7061?R( z=r3)!at{Z6EL`taw-@rbYi5=e_Qvv54FAvIR_&i-Galk{hDDB@)`(ZzM@JLsMuiD6JuP5@+#nH`)+RFR)m&Y5gy(C>8 zB&!j|wppN+Ctll_=SEwAFl!m@>N+M9*TJK2_ol_yd{UU-6k^8Q@;&7@vjF&W$v+Ea z7W?YeOp>~3)n%VXI`*IZQbPIi+BT;d`x=ps$CY@qBmHf@mXnIR38g&>rfj{)d00Ki z;8EFPI{-IWuwF+D~j9KoLG7@xj(cT0y)5gf7bKmH`7>ZFk4CM_w~N zM-+ux#Mz(vuh`Go1Z4(&D8UK)#DABKz4!ySxu+19^xZ@IbM@eV~8?C)zTfcN#8 z2(P_UnKeu%Z}dSeiJ#^CLS#vv)cRycO>pRmAs_d-PXzM5<|D z%5kWkdQ`evB5iW4Z!_H>`bR29z4>YAiZ2|KcFl?5II61GseD$neA79i-GLDs#B3G2 zJb7?_;BMaS(rc&K7MXc9{V2sF3>R^9++8y66QO6Xq7W$D3p#l&he}H%wy! zS7HJapPx8BZyugN0<6YfqyR#cpJ?%4=pH3EGeB3^FA*s!W+xN^12-fy%zDrRlD}03 zFxxD)zZBz#|I~$CM*g~irF+6cw*V`5g7h+`L?57kr*f8%fef%-QVZ}8{{n4lQ3^6V z;8K$W@w(N0E$VqD2yn~{069vX_h7AWI362OQYu8bVYf*g4}3z2G+tiH5YC0t(Beb8^- zu50KbjIDkJ^*&c;1TkhN?pnzUh8Md$@N0?LYp|D@e2oZ4rx)XAn2@Sp zncs}KTrU$tzBY9p&#T<+14o0YXQOS4@{G%{1&>LyUE^Ks0#-Zh z-v&4>D@|W5=WSr#0PX6T3UK~}cJ)QlsnI_sFT<%?3V`ZH^zZM7j%~zV{iG=d-y~z3 zkXKgH2x}z*y92~qqQ`onx(q-ysB#BXapVv+hOlbzu&Fe12fba%pj1(N7+UM3*kN zv~!i}bo^N{gvTa94|~M6HxK41ea~Co9MA?#SRQ`x;?bILQpo$%1xfcyJZ9+a#dU$z zx$VK_zvDwt&34P0=e2$bB{D;eX}qEP3Z$JQE&Ao4Y!w46W1!_7ke$mzT458voRj_u zBdp06`cOT3*7J`^MdMZ zk?gFI#87VjvHhFSA1h+OmziKYQsj5dka>!wqX)>qPAfO)>3OvjxNtUJYA!sA7i?0h?XwTDm=Be zVI9`C#wh_~S!WMKgL?(`qNZUR_C(t_6l1!52&}eY4i-ymPejA30fW#aJW}WP3@lRf z5RJxZ`w%4^yq0k@Mvlg+NqDWsY6g}b0$e48_Z4Tp+1wasZJTwxyqGruCc*}L$_mYy z47ZB>qNJ z^&a<#&kEo+ML?vHsxC5>+_wo(K)R+%@W?(^aNS@j^(Z$|&`LO6w#PrZH%)QPKa$^1 z$e1L}q;_ez43J3aT{UJ(zATODwG+@|T%(I}r^lQQ0y}*xJe2p7hI`j!M){OLd$-Nm z-4O=!lU=^yvkJNSjqr(J{2ZL|No0)kF3$OC$&K>~W;w*ewTt4G$}$~vGS<`=7h-2h*%Jxr7pDz`@Y%z=1QRmhwENR{I)u;8oH@jQ znfStu4(DWf85uqt4*=nYf!asM4}04)$_o~2h*6mwG4>+94vO4QSd9aGbE=HCDBX)ia{}iJf@{J3YflwH;myz( zUn>EAxlJ;K&EjE!V<)^Q-_5-O;%n(h-Mbh0e`$2y^^K(+D zqj0TPdG)+Q)mTpW-5g5g;$@@DBm`lQ2iU^wWsqiSnD8o3;j zT!oDaby z+qTUwwr$(CJGO0ov2EK)hn;kK@~=5lb?V&B%+o?&n(WLCo zt-g$OVTX=}zD4`>;SBuOt=HO}u>kUpwaNhku7C~hjvf9fUPb>dm0ioS(vfyAyrA=@ z^hcgh9bFKFw_<9YUyN;0I-L zZ&G{hq!IPQ&ydnu9l7vi7pm}P8VixOEIZc7 z{)xDkvB{mmQ?sf&&LEldUs@}zeAm|Bbx#_UntH$u^YvNB)?byKo1Zj3!KyE!%cd7# zip5Q=wN0-|t#4~+88@qS!S(ea2a5rvI?_!reM#!Y{_pO6Clh^nHOGe3@cqRy{)+q$ zpmrqzp%Y@Sg9dmGt%5f{Qroi?`|iZra#kX(6iCas<1$a#jI&pv7#j?J^+(7L6&RYv z6DRmyugax%8*ukr9q=w@-*r1A?8?t-AlWwIF;DiNahwGdXM6_V0L#|jBXpRLiR!_K ze;1{ZEJ`Mk51rw{aK>TQu?4tbb4Yf}zoa?=>`gnTOS|N9;93cRrW?6H6~`agivn z)CdZhVm&D>|8dQn4n44YQeEkg==-4+oW}ie?d)@jE7SMPK9&6^Se=3o-6SAc=t6u( z=IwQ7UmH;{ar3WdyPD9)6=+j*^F*luA|df@i4wc6sJ)wSZ|PiW{A z#~#r&3fW1E3jMvCzF=?*$zf?N3-fIghaj%jk;33t8jWDKgi+VZ3h~)1#D#~Sb9t$4 zE%3L*jYwT>HN)bTM_OqtQz6u8E0jX4(b#lCUNn@FAmr7Q8X@F0=COJ)Owc(LWI0rY z$#GmWgGX%=4TMo$joh=kFV@MzZt6^YsBD|!Zz>ylTS#mzqw{U6hF(@1{m?k%r@AtN zUsh6X${Q|pnpnWotd)v`C)v)Gz|(A$N`qI6v2-fi%J_{mUJ=?M1^1HtY5Ua$ z9{1Rx_?5;ZH20qPyut=lw`;Pnyc%?$mSBa2l)S2jCD&`$u)JR;7Bts%_`JGCXXopk zFuaOmvzqJRI_lTyfC|cwm>~vdrZN1nu>;3Hbrkhx0ym7LOjyMYpreL-qZ1JqMKg~i zmOx+wT*iQQ2U;D_%#o1*MDZZ$9)SSd;Ar7|)Wi{qAjaf@D>r^@N#h;Nb{O>miVu2j zFy+CU4_tHU<;{u@es6He%EB4KF5lH)n*OLr+Ptylge_DRT{wdRwUO#a4R_w_i zfS&Pt?!NvLvuAJx)4}y7mb24+EC>cjh!u5>tL*2P0465JyIkoyQ)H&sJtoDMfba^qpQni_l6s>rutw_3KamuzA@PTuw~8fDdgCulMd>R({Ve*vh&xjFe&vlAkkpPmeR_ z@Wt*Zy>S;HBX>ofg#Yun$a8oxLW-{3b5b!*6u;DSoT3Ee-uQEfBITk4RDj$Q^ya02 z^b>Uk$Qg=X_I-1dfasG<(HsiC;!|g=obUHfd#oIm)RRLC?>On7A^(uf7{SSH?5w)J zIzCMVIOCWBo?gQkE4hq@QroP*Zg{#c|81BK0!W<##pJ(O&hM~f|98|{@c#lMsXAI& zIJg?PGaE3o8mKUnG5>Fel&5m@T^54G-)^v#E>5E%tX9*os6lT7u2#fMtVGgC7)t*H zDR_BvTh{B^t=qo!DD|cBJ$3g0#20)I$kmQx0|z~7dX~%WVR4%`J-v2UF!!Uzgft3# zTgniI6ZLo}*;#qej+zDKR!S?mflgS}QByemS0Q#e2@@~+?wVYEIeeEQ=bmMG{+(7E z`A<76D9J74K0AmZ7i^I+AGn9JGEzO{9z&?JM@hIOySXN8^U0ys>S6t5VJp&o^9+4Fo2q1DD^JnA7LTyc0**gLH{dhMjoNxP1ZbLyZ;?wki)C~=bqZ0H_2k4(Wg!5XXcG(g7T|`?0%-+7@f9i!Arb@4RYcK8i0$A&y;maj~ zI#;1xWB12`4i;KGjH(I}|4djKkv+m6FKihC^!m7tuti&Rcq{r%=fCLn9(-jxwy_oS zR*9^a5zM?xlvystN^6;KmT}Z|QiuPlg}*45{xz-i;wHKvj>j&EWK8)J&g2#N7y9~I z_7PO%?gaBIQmW(yBT3T)n-n`wD$LZD+Om_tRQPk9`32r$&xVj=2R2@3i#|}?WvK|Ck zk5Z3VcF|6CL<$)2-}+krvnG*E7CKuffBbMa{qckU|9wsV*AyooXkWFJ=X>tgz6n`< zeIl@6IGfNP#IQywrX1 z5$D7Mfwn>6NFwHj`SY#^Ok&ydojd?c?2Dm&V+zjf@NtyCt_y+y(<@`4@Ns0&PA4SJ zQygO^P6D$?;-QIzU*T93;kfe@5{_0S#1c__pc0YAZp_(xCLI(7TceL5e-coS;FXCe z&WjTF#6PJ{C7}f=%%fG9Cy-KrXrPZkHGmvzp%$J=5WT&w{1Rm|FMKp}ERV0n_46L?cWLS{|<{0jBTjZ8?XG`Yb@UbTh_0L(812f(jjwo6mc}5@+ldu0^VFI5zRg6-H?D z?nEP~mt~x1IgKVilt-N{4lB5NHIxEvGXepyoeoV2TSKZH8e{hdv|Jpr0l+-l+yP*2 z3r2yuwv!-8f*d1?BUxDu%AabO7R-6GtH3!pOZ2n*0>uu!O5BZR;_2tD$zk{JB$i#j}{!&^D01Ssqx)$7AWd%(8MKZcKa&v@YGZ~^WibG!0yKd0RQg;AMKOx3BmE;57l$ro`~7YYgn-YrKu#|^he$@(hf;<A{C#BydBN1r$cR3F$){nO^Duc*<^fy6GyLZfd0 z5fua$(>gr4^NC`t1w?3O?oj2=ObRtBDN05DR1C%lZ08QV!46+}n+#HTZkbbN8c3^) zM@vwFS|S+b7)YX+n|o3k7H+b zn86A`dpq=?75qb2h0VauwHqgdtU7Ak_%CF1kapVhGUk|_!RN2CaXcr`8V;N!j;*8L zU}r?*!O*nGEieHoxW58w$Ij}mECFW-bRM<8Rpb?F`xj0C7cic0TXoC9SNx$fHJcIv zHdY^_Sj343dGQ_@|zvGesn{2Etq0PRkYdzGeaH8IL}4l{o#%lQbFf-F}fO@+(`br1R9^tj$92FwC>cl(0r?>j^Ef92L6Qvc{f~+eG&f zF>Y-#bqRw;8%};6{NcpkT(l+Oqh~D?NlxO&(PgFQlHzEaka z=9=jEcbPRh&*5V1Bjto??QcC1}pjqs+M zMPdW%U6gH_Rh=0UB}R=R?3t~_hl;fP%M`@ORtA*>E)qGF3AXN!Q5czo(6a50C;Nr1 z}wygVG!PjeAFVwf(u=n&KtXXFXcG(cy~JyVeLKgENruqMCHJ zX>1UqO?WFIy79DK#Y;HjfJ+w%sRWA{``BdW8Vjts7U)EvP14UVSC&_s#h} ztf=5SlREOm30fJdZrt)2V@T=WMI`hxa;*Y#&GU*gL60k_8l#AJo}r}V#la6yvn{89cSll87# z%l^F~@YyOYc;(HytWzFdms>#UZCxmHZYmXDpF7*tbGUKM-h6Q9*i<$MZo#=4dx;;F z@bKy0S!xi>;q8G6IfDO_-qxU8p8(0qOZ*Oci}5J+Q&(o?xKtMOi^GGc!_564_Yq6J z#dHV4nPc)S^~$-6f!Z}&;^AkQU{|hm_b)!s?0TXDIO{JN#lRn0i&=8at}PNiDK?AO z)?}uSszLH4F0HLz?dw{enVFj8OJd4pCVO;Q644vC_T8y)ja(8*@&wL)i#wsVdDUt6 zvJTDE2}-Fbg$)C|9GyM*_U0ky?v2}>Kik+{606{Cjczd7cYW1oP|DoGiMZ}Lsj?O((|>^Dys)t#)If74R#&&7MH-$%R?>c` zKEC3vXj_G=64f;^zg;IzDON!wxEc{dZ=wc6hieUfQ{Qk3m|2@voq7ZDC)7`>EG^Hpd907g%OS$>ur?7%LY)O7A6Rn!f^crI zz>IfuH#~pW_s`=y2`#%b8W7$)wBe)e5X3MQGwR`J^EVG8JE|F2T%GC}&dwjXjHgZm``N?SP~fD^2a0Qs9CZ<>QDj0; znvW89FYubI<|bk$9y5n8}MmLrA1dVABOdTRg)_r+*X zL-OPzH{o}N(m$o4WRoAvZ1Lt%=hlHva=@~p-92PWS4|%-9=zonC=U`3&PJpdId08a z))QatUsE!w8WYy2zmpZ9&d&>@Ze7<=V9rB<`K5XP>Y z8>z33QD7=njhUKC;|@Yx7R7ef0U5ILUO&HfQm0INqrka@GfY{_D2L@5(?lE^tAR_F zc@?NFCUTu3b!;azUL;-$Wwwdc@|_a-rjscr)LnWuld7dtsaK}p7op3D>{f)P#nd?^ zTd6b7r3|`qodo@>CupkP#}L73e~445IZ5c3rV=!~_hBxUPSjNYkb@JKXL=#ZPO{9jbW(f69<$`VfWk; z<~&k9$^jHOPZUqIyZE+J1yj)F>RnvD>Zs>T(s5IMvcO&Ys_GLl9*>Dr=*MO-WyT;= zl=wzkPRbt7$$x%l_aWHOS(e{|<$Ay0K~~T9NEX*rYJZ|;=A(>P8g+eoKidhrXDma2 z*`&>hhN}Kp!qvMIsG$Avn7nf}gGKh^nltVOyXu$3S9+1G>X*W-hk{LQr%sVdO`Ck-YBo*0@u#rRF8?g9^n9ms-B`>)KiN) zP|eBE<=^$hY(vRQR6o2BA4vO1MWIyx5KLupVV-4aC6p|VmZ2$MG^H@_0zW&pQeP(- z0J|24BsD81f6IJ-{4<|~ltw>*?wC&XITkJR%_K~?KT>|rq<(!oa(WMCC}25ZebiPJ zpe&e6XMFM)$80_kQ0*f#SUsUF^Hu)>rUs9N{240X-9gFT)89rC`b#dT+b>8Ss4d; zjiugA_A>+aNI#N)WARHHknXa|(RV7Z?@v=Jhb#Zn5u<6nFh?(MLoL?O5a~UZh zeNk_#j^00c-@Yw-;mcsGFOCx%ota+PU06Lu1dAg68utFz{}>}M8G|m~xbdNqVUYD0 zkW4pPGkny)ywb5yE5UF9C2^;tZSVFDfA<6e@VA)^dE|vL`}1QecsTXO(t>F(C53Qj zA*}A@xnw}zOUj;9dnK^TGP6jQJplIi-+g~N)Inij91z!(lEt)Gci z(t~c6R&bh%mrq)bw14p@1K}I{WI?wx33VDw9aGPsMFFl}Tc1R(rBdKIV-8+eodo;P z+ddwY+v=VOjH-^-6Wr)bvkIpZLsJPu*?LZHx z*2YOOh~nlR60FrzqR+b|sJ8~M)!+l~!%N1)(&;ZJ!ZdmhMJPWWsNX%+`^xfb)JwN@ zSX|Ql_udS5B?ni1!EP+d{*iN6A#d8tQ!OlB} zfB2&7Qm`I)G-;a~D`&{u6kTRSuvUhnwPp=mC;e>?h8RXLvdJmyClvET=Lk)A&#oA% za-Bk{6`__?u(%EUR_EWmG~l(fNOKbtU?n7y>VB_zu+?e48#8kyT<#7!JDYgJ$vLJf zvSe`~29Z%dZ>5yT5OG-8s2I3_Bty8OYbXe5=&g(95d5tpUhE3~5+eN0`{qq5l4p=t zuIixsxFn%_=u1B$AE9>R^8N&4GGBW1?vkScAu5AC16GhCY#s(fL(f7rcZN)zy?WsQ z^sg4Zl!S*qYl(YHS#;KP4<1Lru$3DrKlvAlAV-+8$gwa6nB<*d4{xJMUO9A%V?2V8 zD_l9f0U#bJc_P}2A1Ekg>I5sYs5g?`yp{{gCT3z7HK(L6{tF=Kw59Y8S~}ttBQ@l? z`P`g?#;Z^3kz!LZWKIYdwQ&i+PX=%KTN9j&NpL%lht3;nKm5(L)UmJJ?9vwoI^?Az z54LAoY4eyc1_M+Fabe*}YS)fbFOt?+k?{d??% zaKJj|g#5^UOX<1Dda^CF27->ksY2fTObNPnSo_;wdVS8ZoLYYa>OGP)hElH8JDbP# z&UEu5Z;zuXL zeP{D|Lhj#U6&FshXdbeg<#^M{!)1Z5*A5NTCN6>r(?eiI;w*eaQGun=_I}dr(gqr> zg=PNlP2tB@3RBlEi0nQ5>4>#He^VP`J2w>lf8vMT6joY$HwybL3rPDGd(t7B!gezP zrLno zyyox%hWjoR2d~w)ne!PLc*2T#I;N)-$+@0Lm-r-vuaiV zPQlm8(Q+~==ExfXgo9ykQ~VQYUD&N$A{6Z;to$T(bJmJ$>=owNlW2ZJR`uN6g7=`N zz#_mB69Y8y4zf+0eSJc<&Rjp#K1-e&F24rz;<)&Awm%M!oT2Q-eDy^LEg5OMrf`&Fnwg7L{%eq@V;c^sIGNA) zSu%y*EuBG?dr}_=%Q*jfx2k<>Qhz4j+nFiQZ~sR{OCtqGiP5vejaOpVXnde8X^1>j z=bK$!J98s@Kt*|5mRY-It~pR{Y-)Qc4IWl%CJRYkMXB?ukej`_8c$@SarMMlyRg@0 zChej&;aV`9e2ZqdU_JWM1zdO%Of!}dXxmzeW}-u2txktrl-(FQdV}Q3^HE#PfN&_ z=x;cRdNN!S2s%eEEo%H4H`x6I?Q+-KTerC9R>Qa?e@{4S;;+bsQCr`?8@bq;QDzVZ zbw!)kpN=?}{@KAC)2E-Lm_3VBmEzf z)I|N_)Au8oD_|zUp@Xczdo%rDawBV-Nz-WFeUhZ(1$mVSFs7_$GJ8Po^=B49p3Ny`7i6A4w zx|{-Q=Ccj*WE8%M)qHZ;il{LSZ}WX<*!eKE(#|MZM*Mi*(9MJ8yKB;GyEMYhq~M@b zQ{;2m%!kkarL|{a*1;#S&YyCC!QyCV`WUi0o} zu8;#|E2c3r6kS<8tuSPXhn*3np^*`k7}PPt{4I#2!Y0GKXkuR#6D8>wl<+CPA;vCz z8Afo;P_94s-_{S}ZsFTdkZ0oYPDluqBOz-%SIj|FEs?o}M1?t4;ShxJpk_m?T+pL^ zy-X-fA#gpYn0=C5DSkN{c&+G^AC4?(OHe~-xiU6+;bZeDYdlHbPJ(uUN6ow>E+v&+ zvL^eM7Tw~}gzF--4{RF8RF~nZi%e8RG%jxS} zW71hmMB)-azJruWYEc7V(?$C~Y!%!IxT_P;;NgbqLOtts>n93PUYDN@&<)rkyY z(i#It=V2JZiBa+FDVidwX)Q01?4D$5itaKL18tle2QXFfIuXWZ(ZOPx?Rx@I8pptLy;oifRidoddeVA`m}|%wUFI8ba$YVROA{L3qg}t^fT_O=aK*N_MgEQmwGhc)pa;61p?XXfTR@xD-%MqVC ziH3>{@?J|yla3AL9!Wm;mq|*zJ$??d@)!pG+SR#oQ6~teju`sg{CSWXyCiZeS9p_| z++1UH{!v*u_2#9*B9nM0!rxdufFLQ@($r#BU1$7ui(VeolxvHC2vhO&Iy7sH$1q(e zQtD0cBhvIP=vcZL5349s`E&^d4EaDfP!CIr$B@+|(lq1M*>yXns~xYU zv-iL4ueG29w%k+thQ>GIigg%ypidzQSen_!>~(L0O6^S6U=Hs9w;`h%I!`n2FKfiq z^b;-@=c;Z)VNi#ELrBZ>uMd~J^pCw#epd$$XMq5voUH)bSo}ux`1k?+o=Jv97AtxM zR(deE&cAm`(FtD1a76+G7A=YeOY#3AEI$lX{um5Uy`hW_tucZ21zB?m_1x3j28KA| z_(JOL`>2dX>|3L3+EE=KEK4bK?F-0-d}n|1#X(<;D6S<@1%PyK2p>imFJr=)F{F-6 zS?R?Mco8%LTcWJD5!lgl&imS0g)QqpIuI4a7~4cR?%Xn8D@-22Rc^Bfe>KJ+zYn zGvYuMy$}ujY1Z%~Q)Fp*dbtl(VZ9MGeZheLFMWAG`cpeg6|Mvd`47npklKd8^++_m5o@Sj(75rt56Hf_yf|}*irUgs30Lwa-Rf9&vR;sCwqQbX{}5Q3 zwzk7&Pd?o+Md5Di{tCp+t|YcY>`>K;nf{ol&uZHwhQ*B0Vz~fow`mX-Lkz^|OLRF^IZrKAT;n!1^bS;>w$A$Txnx@}oSSuc&Prk?$TIGuf@u77TaVw&#XGw;uEsMdEd|;F-@xSOrEG zE_@$isWjd7sdd;fbe<(!-r~DZR`=lqDIMuqTPrtbX=xkQEXlmM@q~6l?*tjK$^x#9 zo_y&5!P5Tb^E=x=AKFl}PSy%z3S69EXSL2eP%OxBmsIFf> zbPK`OhSi!LS)D-D64M;S7;TAq_hdHtBg>PjcNIji$n3hQNkZeuLV2S!u+cE&G+bAW zXl&J9f;s(lLl3uxUV>#9KARua8Je-Jq4Xj>j`&BEz#VzQEiv(;U&ssbgMrEpB`Ij_ z@!iV`*Q*cuC@e%FT$eve@C)M-++>lv?*(jfMiMN4Q|Aw&zYe_%`R{;VzbENB8387a zn6irqB{B8H02Sa>GZD9@me&uJ4u)?G;)&_FT#v0gkewnMhkvKWEv{)xQQw zBq+E47&6m3H=%uY$q!ZC>;<3~PirP0|M&u9kqSZ}a?6adNRrEww?4(A8g`jj&P9|r zRh%1zrS|QCsvC?s@Nd#fIGCG|>_qD$HjDA(jvt|=(&@sMKtVJJ ze?^Vh!KL;?XEvs8VzHTlakVsf^NWyI+f~l*?cH>>>laFs zuF*4D5&GxBmGHnkN5+ubO&D%~BcaJ6dhiGD0Z5&n(#q|@CZy=S5+&bsYeL1QWamo~ z65lGcPv?u1`UlvW06{P%?*VlkpwPPDbQ7G|vkW!=Wb;hz=C|I59+duhC}yX7L6u*W z&1=~HiGpXC4Qrc-GO@by`P*eYuqMWR$iPLv_$HticGq&evmSPrEc*H`w7uhF3uc@b z?)V0&XA3&uX!BL==0op8A4=dnwBO|>Lf1$L(|1{^1@|jx9{S($WJ0@$Ii{}&k>Cz8 z?ft(dHo^iD@sqqZnL^=%VFO#_{`hqQCNYCNw3a&x!FPR>-wc~?AHVPji3|>ewSs&s z=Lmjc3cy`SJ8~QqJ5oRoly+o1%^uzJ`UdO0QW|kG9}@WD_8 z2AP)@f*XjS8k89xpwo@?@0)(oR)(!Pg7n4HKET6J?2g2B5Q4s8cp2P@^<-K*L+cM< zN}o?fQNJcRIVT!dkz3MTl8%r0VjB>f8KLO*MF%JcO+6!@IP!lJ%>#Ul0Gnf*q@?;S z{ar1r#25Zpwa0%D(qAB%kMJdDI{(J+d|XWJZwviL9zGuEw{*uTt&AwI#C&8oVEi~D z6i+Mexvj2PU^MVMZCC&O)gAY+?ljf^-b(HveDKKZ{zq%L(uuI`f8L7Ry&uB@=@PZ1 zJpGBhFp{3|gw5?!u!Qk9WBeXGc9>BbH9$On4ijy|4>aZ>kYs~pQGBUlZ7bT8v@lW1 zEBP^9A$I&ON-Whw+JDK28u`dUES63y^sdq+{MRu?pQ0NM_NCnCkADh_cog|7|3qoD z?FcvA{iq^E+0?U}uKvwG6pRPhPEuBgiiO-~1``g`zd z(b6^ZORZw7ir$;C-5cHfN|lh7Cc9in{i&?1=t7LC-tZg!LMwVl+6Ikv`J+w59@Djv zZwE8@U)cVY!dp1*3ze`>BJNA*z7VDFRBJ-jZGz)XF)% zVLs|2_5=6W#W?&#RO0z0GP3WpYFfD__p%BJr-W!vqoS`^K|3~gMxA}??_1` zUYcsn19n(8PGubUBrXP52-iQCPtJ#{ADIencPcxEP0M#j0a9t((gyX(p-m{8n93p_ zQoCPvw8ZhB^c@E4`D1EWnJ@Uq+Fy(pd7y!!&Jl3f$vM?%C=*K=RYudC%S>diruh9R z8xY?g8*~3`zcPEY+d<-P=|Pe9BZFA}G)~K)y&p)SpvX{W9HG}xp-2cjVZ&X+om>zK z?qIX+p7Y_&s{%0$mqQ225ZJ=D$`!e4G;kwH82wZVgUX2RIft283B^+2{|aS%i2}tA z?$rL>IlL>4dM-6r?K7xmlxciqs}|*fgIALO((PF`UBRl4y2_ z?9n(Y7Zn~X{xr+HM&nEFp`80{mW#*f?!>h3 z->-ML0i4yPOkf<^s1vLBEh$(G_BdT#DC4^2CknCZYs9unz}x; zQ<9&dOE+e7&VPgMdDJPd|FlJeqsQRf9tDL%>n+|R$>O9NF-=dR4WHlkAvX^r>dqef-&*fA@YT#olXZ?TX{%RbtWYL z^F$waRB_2BF!(C;x2aW^T`pGE@&8zp3P%5`e}5Czi~ld8%JN@C)%U*>RRW}+AP{6? zP>E?jRMNqOp`yS2=*4)D-?umUpm@J8Z7;F-ltFN`g_##g^H56pVUjz>`Tcvg|h z+vjqa#qi_ECT~u1;aIfJtU#_Li%1ior@tJNSYM{4PmAR9pL?A7Trb1>oV-o(5tliVEFIG&2LP)Y6FxDI4#R#E77jO!$pFd` z6Ng~4=pIT>E-_+@^*AE0{CW=KSDt~qM4_!1TPPzLH%j-Cy^9mELm~Ic0ptqzGBpf{>2^sL2^!f|H>aMqD5X9(ytOm`VvY0iuhj5UD z$PfrVn%!lfZkOj);24k>f{z&C;;_E!EeAv~$^+h0r>8uozxjLDCGhVd8la~>CIH7# z=yNI%a|E*MO$qZK$3FQ3A*epaKeO9_l9&Y6k$)qU7l*2+`xaeqdYBRLo+(beRDJWn zjIOuIK#!3%2s{+YZq9V|W9Zx?Wt@Ff_F-=8x!)coOPMYcyKbiQsV9KY_g2WAAQna4?)I9#o&R9fJr=vaEk~>MxeC8= z)wi;@Z~lW-e@$g|<%ThJ0P*#XVY*g3K=IY;m8yv`{)1KRraLFV!=TI6OPi!5vq>Vb z7Ue!G9>D)r^XYq}F`h%)OLBDOS>(djMSt`b^8Z&9|{^dzH8vQpxDnQn+^M(7R_>6iN4IF)!p4<^yj9^=%oQ$^jB z;9NU{T}(jtd{fn&VCBXE+ilw(JbbcD`+P=f_RpHLT{3&F=_JGN6 zUo{bt82s6Gvu|Kc@5*WekBnlmB))7WuW$AEkJ7{rRHW@|%3=n^MXkBP!QK7(6vN-1 z-3d95IGj=Y=}XH%+OIikwgc=V+W=*}dJd zS3NK?*Uy?p5f6(uX*R{6Ht+PQRbd%A1QX}*p?Z?`Ky7rZ<0xY6-8tnGar$m=hq+rn ze01;9hAWx^dY{3p?@kMsaWv%B>f-giS7o!y)%uq1VY)7)1|9!WU<@ZGL<(V=QujT^ z1+G}z$c3J^lXOE_AVxNIQdc@&R?lv-7I2(d4|mCDP$oXtytX8Q+`x4p!$MG0>h*gJc<`*z$0@3gA^*{ zLKm10O zGl+^2(;2WC&)a`NiqH*Gav#bIL|NyKAKBG_TKi1~B3r2vH`<=M8!}MnU+ta2IrL;} ziS&<<@zq>9cvBQ4wSXYmnw%H4ztC=b8|%Kda5|^MP$^Bm;6v-hN=0<)^9JQb4xvY? z>pP7Ezzuxy9P}I;+{z?n1$Y>6rWS$`D0JUMEK~bO$nE1POVM50z*-NN$iQ2vA4Tat zE2n`0)%bjBx_)4b4yJ|=px6$s~f#W*C#1nX)YOZ+pv_#@0R-VRAcq@VhCZ$x)$5PK@l<~N# zsYC*B89+2~AAlWh4&dEsmneY8siV+gS!KPQ=IaNgN*2~N8_BZ$d8^$-L39IOmfq+s z=$}RG7`(g6b@k;BUQqd4Ys5Q*h*zGWyrCU=xO5bqTaAn^}9A|I>icVQ|e5t42Czcaw=h7%}t%@mc)w<+rE7`o{z$8XH7{c5X z@=NmDE8?)jlajlvux01TbLJQ_}w9GehR%gl`KGKPYSpe23e~ppnX;$xCAST0nR;8+QpHuWJnom0rBwe7`$^Vg2>^uL zMo@$s_g1R#hP0uIU@FTAMy}ap?dQ4#qHW@q8~0eM#bmSVI{=k2anHoHUlCRy5ERvX zd;?7>>k-e3L1aP*;YE%Q1T*tLXqBNgV6S@0S@lckE0ORl>rwL27eFxQ`A;hYGxJfz zD~aJO`l|YG!>O+zc_*Nl?kXD=nl7 zW~^nt5r5_2S<~27JWxAr8hyJ|H;Qyp==tYI2-Pofrzn%tWJv{=a)63V~(*wYXQ%>##I zSpt4GpXjUJo<0nt+MOYnm39@x{K-|+=yqU$Z^wySpP55 z?yGq!Epw#`n*=-9Sx+qP{x9dqS*-t}Rvy}#}K8>;G2j-7RWbO)RV`9>ra(r}BQ|ZUmq~Fin(`(*05y8KD zCI8f?5Jws9J`;)d6Yhv&PkKqgS@?XfqN7!AaXD7gFmM0ZJbk7-=WONh!9+cac}Tyl z#(V0JeAT;4CVCS77GKgMjVmSLBO}yoh{kjBf|1p6i@OfZwBI8rchi55(SBm|PonmU zh-@821-uFPrUw7mHs7}6-=p8>_aw@`wBIHF)2mJ<=14m=1|EP460-!qY6$nE%>B}b z_2V_^*gOZ}L3>)wQWuHl8WB(F8NP6BY3+moq07P*6Bpu+*Ewn~ht$iSxw5++b$-3) z+K|-Vq{YR{y1M!ji2b!M-TbUSRs&H=y&UqFcN<9;R9RRyb{s$J3$40Xtp&TSlNqzi z%`|C=Rg$L4vi+E$iAAAX3lEk&Yyb1~FTl;!hJ3@;3hUlZNqK4)kVYk@ z4%5=G8FPB1*OrVeJGBVT*w_bIR3@a22-#|ZG(rkgmX5kfq=i0!mu?i>G`dsfGg7K2 zP~`>2m|+7ah?}gkM;ErF*AwwzU_$R#p1v37`a63MuB1z}hL7|oR;A&f843##Th%$k z8wt|J%=J;9*rO6J9KF=)sVO2b6Hm8kCBeF;L_yfkFiaun*;{5UDT`VjCd5T)s+IL6 zkj0sd7~U&(i)3rAX!V2sL z_DUm!y}QOh(@uOYQK?q#$oiUwQk9yItfXo5CIffU`th~p*tVG8$Tp*5Da%|pK0eAT zrQmwvuC`28f$S$jCAUg&v8^vdvk1nO|BOUIe7jUE6QyBlGMZPSHoYqlS&@>ph4$Xw z(n_nAWo@#&^l`UdaJ}MC&gf&lB$q50k?{2iJxL!c(rjnjSUg5dI4jUup_Z`)IEIN)A^<-W z3;$24%4Vy!X28f2bFtM2t@%@`N;@dXTP1T$_{lh(yOT&havTfP^b)%#te`otZ$QNteHO$rSUQ>T%QoWUUFQxd z$0Xfo)J7xBLWo0X%*8dAJBp&kAqPrxyxs@>8qM4^CqmA{ketI^(#K(@04@v4TW!s5 zh8^qIY$Bvi)jhVlW6^xgCZ#@Ob$zTrUsP4QOY(+|UFwEkA%Dhpb(`_IC<&k0{{Zyc ztphoasDN07Mj%AU{(Eu&i?FiV zdc}^^%pOb~bP=0{qLVJbQJyIODO^JoYDmW)a`}CF!vR58W5xBzo8V01=dfEMVrje* z5j#8kuK(bhr*3EtXv*u+8kwKo(|O&9OV%3KwidNc5S-qMP06o#y7umr5T{2bAWIOc zqo~-26IT>Z@%dT!=x1Qv8v&Q(q~{fKPDUu`(9y_f8vQs>gvl7B!6`xk#x@}ePHT}p zIX^!GzgISf0>LMD5z;Q} zCaz=cI#2J=lJMoDA^W7fq&8`Js#XkGHC90~CU*x{V2S>jVPDcAw<_k5q1C zM<+On9I$j=z7+N|I$a$hx-zS+`=knVikXn>tk8>6{qFP;OE}fXic{4lfi849`%;of zwHk%BN)wMoUkW|{O4L{vd6Pgk;%d%L#{<&8Q`OO2&&|1SWwTsz2+9O^+-YGUC2`Rd-{58xd=bf@p{#1ebascQH>VjnM_0>dKEZjaRzD-)H9w@XZtU*#XQKTPy1s0C z*+L0=L1lMC*Vct%H&+L}oXPlyKec`6yNF)6C75_{Y-~+M579KE<;Z6r-Yq?lQh4?J zK=Hdag5v(Ah2;0>ND=G0;d?+36ARGKq3hKg$FjRXeJAU-qy~J)Woe%Pu?q4w((?kI zp;G=fK7l2dB<0@G1!TLA;C_6A-Rs-<5e@c=`chT7=2C0+=E&Q5dilEOW8n_4dqxg> z9QIz9+FFq4vUtIxmid~W*oxYchHZF1baN3k4Fe`Gh%~)MqlKcY>mIglMf8qhM+@TD z99*7uk?~4PNAp{GE15o;db{q=?+^1eO_h`DXZg_tqS=ZsvmdT|YkI~2a5K%4zU=RT zwbep7x!BP}!ltreKeekty{!Qx0sS_!(8a>VoEy9S$qrjITF{&gckPwKXDxA}YPWcZ zfs^fa>Rq>rg|7X8K?kG0jjT1i*7c38Zq(_heY^Cv3maE3pXKS6Hu@)M?gx?!xTb1! z2!-lkKb!wPwDILcgfZ1)XaA{e1dkeO>q``d+jhD&pm1eF`h77%NDP%Tv>u zwP$2zN8*gjMw2353WXMmnP>KIFmhYe;NJD(t9I9hV5sk6#w4Q)hbD9KS61So_)CgJ z(Z&*W6%}iGM3&(B7;Nfn6@RAofUP(uUo4T+X!;nj>i@Ey?w>;>hlP3V_SWc{H|_mw z(pV8~Rh*AXchg^s(}bKw(=E7*B^xvqoh0>$!nDoYM5*5#>uzMlX0va!H>Pqx$)TxQ z)WOyNe5ln&?7FU{VA}=lX)o|;)t@81c!K;DskkWO;!4jZuB{IKGja7v~P~gVNi1fM_tgFhS8tJf8t%P-ItsR3FDR>=@N6KZA*G1 z=Z0N6E6?az%cSJwW6=7|xAr|%9%ddNEPL81FR?i{h>P}|r?&Rw`|g0{eAPkSx)2Pe z22Hd}$Ga3BYV|x~K*rLv6$9Jd27V$6`>0%V8KimapxV9NBnEymp1HW~NxTXX@%x8s z*IIAN3z}mJ&9dpAkQ6HA>XoYQuA! zuU%x~6GaU)tE8~?kKx3_G^48Hl2TKVrySj{!{7Q?aAP?A zIDkn_oUwU;x?pM*x*}>*x84M0Nc{MTroJVz+Xyz{TCP*iVTh z>?y~mN7;m8+i)iHz55o07)mL<9i9-cd`GPkI}9v-L)N;K5;81zB?dMEd_Ly%uKx1Ncd`A}03_)uIFX$`&UYWBV;R@PJ|p zoUjGc{C9{B&G%`&nC?du>914jU^2Z8So*i(#^zN9&=`A}Xbo6g*rw}%6IX$LU0<@^ zpQpz4<6An^H}E>)L%zj$VW7+mi-fbNT*>bGWuOHisnKUfjDVKT^JK~^z{wG}7*4eq zo{0_-aTMpV*K$J@br|`bLH{a64m34@shihRVE^r0!x*%(ig*}epu>K+gw8M5^`FX> zBiS;E5#=(ZZx)TY4^t;d^#LC?uohdMloo?VFO1$WD4I2i3(!}DUQ(-eXNtAFwm_eI zWQzGi@)_{JECtz(-b`(Z84h7&4aHGTAmKPvfkkp8iX8xb3~e#A`2(R}2KSpj0Mf-{_S3L= zrOmibHMO#jWi~*S5!>@Bb?Bk`7V%S;IoQM}99{Yz5OLMBuVr>14!jM-j4^ylcm~q0 zCr?AtZ&I3)qyHOojeO1#d&Xpadp*N^U8uPMiqi5kx*c>zEKt$7Lrb zg2&61U2R;UBun3{DT8LeaB8UH8en8432Q!)mLvK%XNY+L)!vn2Evt+Z{&Nynm!J6; z+R@qM3a+@ER-Q!h^t;^a*T%2O{0u(zS1XE8JLucRY#R)7#C zfy&^Hs@wu+DNOl zT6jTO&tzt6f=b0zPG%3!P_EGHz;a@9H4NG{80PVYthF_1@7(4%Fau4<^HcA(H@OI( z8igINmkrKF9Jz6O4eU=3wg&gJ}+5Ftk#%@~}=58U#O za5W}yPZSpff)R#qFwfyvgCivT0MhB8BS*T;v3@5?LHJhhu%b1VrS3ags=JpGbNFnNmp` zQ!QvBe^qM~$1d4q%RyQ!6y7atwx}z4CRog#`<*xGKlOpEm*3?$ zur0mxw>IhSklDr^zbaPROzJes%>xf0Hz9@ll|DgXrJoR7dE`e3&OExkzEZP+D0Wj= zZec9aM9|MbI%k_DRuF@2a4>EHR84l&mWfh0fI0Asl{6SY{~5B$1+{U6Bc{n1>7gE+q92I9pqx*r6bY}Z zjD3$X{0#VN9OK;(UpFMR=D8qb2GoYaf+SkY*&<|y)Pnj>7ClNxcjav=Ubd7rcPP5OYR&X5lc>{fP0uE6iC(**4I9P{Y3EoDfhJp- zi&eRLUQ_Gw=ESNZvE!%6E<{K{@wS4*C}_=O1J86-k&-}-?BQdwb9V6tzkOn+hb4w& z9wVYXu0S16v}NjOK(krYZ3*@t%QE&PU(sqIME4V_qGX0-u^qYbazUcL_Q2K?LSNH^ znzBLvzAVxZbk-SV7@A>_iGSC@)24^Y&KFW0hA=o za-m1^9lMiRm`mtrMe|17l<0Y<1v1f~-ZE=ZLugCuQLDHq(=DlXHX`&baTC@+_->Ex9kN1xtoJD%HR(FwZOn$+ z9&lAaRNpLFBBY_TBKQKUv@6c0W<2#yMIO@WI?%-M?lkwXJT(s*|4FmBtns)+#`o?J zx{ekZ{Y>YUz4YhC8Hj9+;MkQ>#+m7$Gjr*)$EP*Skdq74f0nRl{k)Jjx_rY{A|{MT z_2(yid?z~G^K{_hTzNHlF24n_=!>BA`GnGm#6TgT&+A$(y8WdGKC^dp%cbX!t*MPt zGbr@)1!A9-l$`sPrBf|jmmBOCMm&dpG(vnWFFHVx0Tm$oH!)c#d8-DDkG!r!NV5+v zj?fJBdMH$alG&o=mSN3Ta23!mPI(#|bb{%V=o3`@0er(;sTZR-X4NsxhLk|~NyCPO z%Afg-2CGW`^+unUDf35E^ee@oGWwm5M781a^MEu%ewV-&#uG`hcsM&Y^1xoW_MhI1 zF2bdiNrk-I{_}%7{pS^VMNSb$lGboOj1bZ3-}NUXo6TD>=nlL5-E;Ky?oEktkBoh_ zI56J)kcB%*AE~lE7wFb(HD7x!KH+m}r~-4xo+yk^o6TgL2zB>@&m>nFjLYx=qKuP1 z?p2srs_wuKq03|rcBVhoygj=+<{R4K!Ymk}0xNUmtNz>(1OZswxp@%RB(E2mV#?Ey zeFW!H-Vn@WaR$Xn0a)il%hzA`jmRa!YfGBVCitG!5N7Q02R?p+{H>t%-Ujr__Xd#o z=K-N@Pe`iolq-D50VC}O1S@>iRyn)tBf_^M0FQX<9Hl0C=PTu(rWNL=Y1LBg$g#E- zzSY6tnQ4Mhxq{L0Cj3S3)|b=zM5g-Aw9<_lpx(Z#T0ON2JS3_j`aa5kqchxWfzg@# z$wl{#!|PDX=xvYCDT(V@0keI4eM3nYiaE+n^kR+i5oNuj+H~W1)j{;)jqwp^?d;Y& zi|^4>=YjBnk_YoOltggpH;MleEAZuQUfKUWQt#t4i@M~lMg8@iX5O!FgVvKgh=0rX zcAkg#@rlaBFW~zksPz(>3qnv_yN9F^6*IrR#|X{z+-HXTQT6i6Cr9KP*(ZMSi>fv0 z*R7ln_|tAfZHkCJKOY2roW=(l0%A6OFUAY;)Elzd{={fchVy;}D#CYg&>8Exb!Rli zK29q*!aV$etj$mhgP(nZJr^pJML880hk(O;Za~nzXf*aH!_t0EVtGuF!#^^gw8&sd zqgUwe@+XEB(Z~VU7jx_gq{kMqFEXZkR_@&lNa2O<5S^m$nuKG5kh2_Nujt1Zp4O1oY9Ep1_ROcMXxyh;f*p`oIl9oziSN~D z1oBsS>1PTM>}luSD{(!%4Y-_SZVjo-XyoLWFtX!-EzkZ0|jfV&BHuz+mnaKL2mtce}l3waji=!6k-x(a1M zBVhf>TaQ_!)}lzxg*oC)+)tPyn^*>B*J8@ruy2ZMeG=&g+~YAo1$~uF1ky)?1p9+< z86h)`7;vR;pc#K*|0n<`!h5K3aI!|2E`RrKb>l$!kw|t+j7T@h#rkynp`Ih=Zc8yi z>BEh8T^Z58sGRml7~z9Q2Vfm(;n5BpgHrt(MEC%xD0NaY{U}2wl_+4Xf~ZCjl>Jxv zm@`OZ9%+5@$5tkK4l2{7 ziUm$iiGswx-&9y-UNW)8jxx&+%!wy2rybwfLXD?_mjbl#Xgl=Jg z0&Y!z3AMoy(SQ&Ijkp}FZaV;?{1edp|DoAd({fx~1)lBWPewtHav(<#qZKL{VjgSW z=aYiP{H|R=bv7c7HgbgrDjzfl#l^$l`vP$w?ixXX_}9isgU1%OaA$6bwQu%H@p=y> zSEa@+sVz3|+Kk2@?kw=vc?e+;LG_I7PWp~Ub)Dq8fWP7)Z1vyw{{y^ivza#H_(52Q zeh^l{|Igqhlm7p!as4mDswN`vQC_Q{U}y_W(wB;;^?x(0YgHSzo}_;&!WoBefw}{3 zj54*OSmQ*D>Yb-EJD8v4%#JUfXE1=+YSV^s?MfIzxT)^1r99>Pe*ZA6_!6lpwSucGB>W-wq0{GpS?|Z+Cg6YsMUIi{>H)m&zQs%@33Ph$uvAj z-3DQR8eHZg6P@S-z_TDTte6_k@;Ef;Pe zk{c)vzbzYRw0u`F53$=GhYh>q^tq2f<(@HkCmy}~t&_59uQs5Q(JD(l!o;bE9c71% zE6X(k`xq#cVN<;63idO8S9DR}t^mOO2}(VP2b_@ak(bGA43Z2pybNHy4L+{@=Pup3 zL^hANW}#pmmtCWJq!yiF&$~}J`>H3rc}qreqohjN{F8)j z-AIWsPf?eX`kr1j3sWx-ZAyWCTk1#SuMHmA+PnPE9r7qqJaR7DAf~d3rIe>tGuw`f zXMwdYmDHSQ+2ADc6S<EHI` z%ws`m8h>7$c7D5aK4&}6cjd_6^X02w47GdmQ{wvDn7iko2dBd%$lA{PU|F^zID z2d6mOF*B*0+PH$aL$QhFVHbuB(~MdHnVLpHm}6O?&L@<@k;l`FX~a8zJdDW^j_sKC z3g-U6a*Tb5C_|*xZS{jDim7zPVF9#WbW9?3spF#IM8)A};F+Xm4z|TaX5j>wyT}c$ zjG;NkZKi-{ygslfdNkAjMy*D`{4s|{L>LjR8kuzCqQOMeqDjDHM&W>DYzA=^9HTUi z>IiI5sWf;%T|k7^Pt!U`?TCs|;VF|vv>eu?Y4kJviGCp(NW>Nv)frdNP

    i)-Dh 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

    -lWrsJ6nVC%&>QU2hoi$E;Y3J~Upn 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 literal 0 HcmV?d00001 From 718c2e8306bd61da13de6ce4b4aa5a75edfbef90 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 14 May 2019 17:25:46 -0700 Subject: [PATCH 138/366] Update Piston to 0.2.4 for even more bug fixes --- worldedit-libs/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 37f503862..ef2c30446 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -91,7 +91,7 @@ configure(subprojects + project("core:ap")) { def textExtrasVersion = "3.0.2" project("core") { def textVersion = "3.0.0" - def pistonVersion = '0.2.3' + def pistonVersion = '0.2.4' dependencies { shade "net.kyori:text-api:$textVersion" From e7613dd8795bc8bb0add5f1ff52df82c7d358054 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 14 May 2019 17:57:05 -0700 Subject: [PATCH 139/366] Stop using IAE to communicate parameter mis-use --- .../worldedit/command/GenerationCommands.java | 5 ++-- .../worldedit/command/RegionCommands.java | 16 +++++------ .../internal/command/CommandUtil.java | 28 +++++++++++++++++++ .../WorldEditExceptionConverter.java | 5 ---- 4 files changed, 37 insertions(+), 17 deletions(-) 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 5f5229aeb..6c370a1a1 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 @@ -47,6 +47,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT; import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; +import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument; /** * Commands for the generation of shapes and other objects. @@ -203,9 +204,7 @@ public class GenerationCommands { TreeType type, @Arg(desc = "The density of the forest, between 0 and 100", def = "5") double density) throws WorldEditException { - if (density < 0 || density > 100) { - throw new IllegalArgumentException("Density must be between 0 and 100"); - } + checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); density = density / 100; int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); player.print(affected + " trees created."); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index a8591e1de..ec3c09e4a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -61,10 +61,10 @@ import org.enginehub.piston.annotation.param.Switch; import java.util.ArrayList; import java.util.List; -import static com.google.common.base.Preconditions.checkArgument; import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; import static com.sk89q.worldedit.command.util.Logging.LogMode.ORIENTATION_REGION; import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; +import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument; import static com.sk89q.worldedit.regions.Regions.asFlatRegion; import static com.sk89q.worldedit.regions.Regions.maximumBlockY; import static com.sk89q.worldedit.regions.Regions.minimumBlockY; @@ -125,7 +125,7 @@ public class RegionCommands { player.printError("//line only works with cuboid selections"); return 0; } - checkArgument(thickness >= 0, "Thickness must be >= 0"); + checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); CuboidRegion cuboidregion = (CuboidRegion) region; BlockVector3 pos1 = cuboidregion.getPos1(); @@ -155,7 +155,7 @@ public class RegionCommands { player.printError("//curve only works with convex polyhedral selections"); return 0; } - checkArgument(thickness >= 0, "Thickness must be >= 0"); + checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); ConvexPolyhedralRegion cpregion = (ConvexPolyhedralRegion) region; List vectors = new ArrayList<>(cpregion.getVertices()); @@ -294,9 +294,7 @@ public class RegionCommands { boolean moveSelection, @Switch(name = 'a', desc = "Ignore air blocks") boolean ignoreAirBlocks) throws WorldEditException { - if (count < 1) { - throw new IllegalArgumentException("Count must be >= 1"); - } + checkCommandArgument(count >= 1, "Count must be >= 1"); int affected = editSession.moveRegion(region, direction, count, !ignoreAirBlocks, replace); @@ -433,7 +431,7 @@ public class RegionCommands { int thickness, @Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air") Pattern pattern) throws WorldEditException { - checkArgument(thickness >= 0, "Thickness must be >= 0"); + checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); int affected = editSession.hollowOutRegion(region, thickness, pattern); player.print(affected + " block(s) have been changed."); @@ -451,7 +449,7 @@ public class RegionCommands { TreeType type, @Arg(desc = "The density of the forest", def = "5") double density) throws WorldEditException { - checkArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); + checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); int affected = editSession.makeForest(region, density / 100, type); player.print(affected + " trees created."); return affected; @@ -466,7 +464,7 @@ public class RegionCommands { public int flora(Player player, EditSession editSession, @Selection Region region, @Arg(desc = "The density of the forest", def = "5") double density) throws WorldEditException { - checkArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); + checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); density = density / 100; FloraGenerator generator = new FloraGenerator(editSession); GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java index 395153e7e..e3032fa95 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java @@ -19,10 +19,14 @@ package com.sk89q.worldedit.internal.command; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.sk89q.worldedit.extension.platform.PlatformCommandManager; import com.sk89q.worldedit.internal.util.Substring; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; import org.enginehub.piston.Command; +import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.part.SubCommandPart; import java.util.Comparator; @@ -92,6 +96,30 @@ public class CommandUtil { return Optional.of(builder.toString()); } + /** + * Require {@code condition} to be {@code true}, otherwise throw a {@link CommandException} + * with the given message. + * + * @param condition the condition to check + * @param message the message for failure + */ + public static void checkCommandArgument(boolean condition, String message) { + checkCommandArgument(condition, TextComponent.of(message)); + } + + /** + * Require {@code condition} to be {@code true}, otherwise throw a {@link CommandException} + * with the given message. + * + * @param condition the condition to check + * @param message the message for failure + */ + public static void checkCommandArgument(boolean condition, Component message) { + if (!condition) { + throw new CommandException(message, ImmutableList.of()); + } + } + private CommandUtil() { } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java index b200e11b3..5270cab87 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java @@ -165,11 +165,6 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { throw newCommandException(e.getMessage(), e); } - @ExceptionMatch - public void convert(IllegalArgumentException e) throws CommandException { - throw newCommandException(e.getMessage(), e); - } - // Prevent investigation into UsageExceptions @ExceptionMatch public void convert(UsageException e) throws CommandException { From 7be00cc773bf4c5888d5a3396b16f68068e242b1 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Wed, 15 May 2019 20:01:17 +1000 Subject: [PATCH 140/366] Bump to RC2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 839562495..5623d8444 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ println """ allprojects { group = 'com.sk89q.worldedit' - version = '7.0.0-SNAPSHOT' + version = '7.0.0-rc-2' } if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost" From 71df3716dd074cdf21805b898ef66ccf029742c3 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Wed, 15 May 2019 20:14:30 +1000 Subject: [PATCH 141/366] Back to SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5623d8444..839562495 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ println """ allprojects { group = 'com.sk89q.worldedit' - version = '7.0.0-rc-2' + version = '7.0.0-SNAPSHOT' } if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost" From 3173e2610939f5331d1b035019b0ea4d975680dc Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Fri, 17 May 2019 22:24:14 -0700 Subject: [PATCH 142/366] Fix //expand, improve //help --- .../worldedit/UnknownDirectionException.java | 1 + .../worldedit/command/ExpandCommands.java | 152 ++++++++++++++++++ .../worldedit/command/SelectionCommands.java | 58 ------- .../worldedit/command/UtilityCommands.java | 4 +- .../worldedit/command/WorldEditCommands.java | 4 +- .../command/argument/ExpandAmount.java | 51 ------ .../argument/ExpandAmountConverter.java | 70 -------- .../command/util/AsyncCommandBuilder.java | 1 - .../command/util/PrintCommandHelp.java | 25 +-- .../platform/PlatformCommandManager.java | 9 +- .../internal/command/CommandUtil.java | 8 + .../com/sk89q/worldedit/registry/Keyed.java | 1 - .../formatting/component/CommandUsageBox.java | 49 +++--- worldedit-libs/build.gradle | 2 +- 14 files changed, 209 insertions(+), 226 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/UnknownDirectionException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/UnknownDirectionException.java index 49c323d17..a5b7b6c56 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/UnknownDirectionException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/UnknownDirectionException.java @@ -32,6 +32,7 @@ public class UnknownDirectionException extends WorldEditException { * @param dir the input that was tried */ public UnknownDirectionException(String dir) { + super("Unknown direction: " + dir); this.dir = dir; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java new file mode 100644 index 000000000..e931f5225 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java @@ -0,0 +1,152 @@ +/* + * 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.command; + +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.annotation.MultiDirection; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandManagerService; +import org.enginehub.piston.annotation.CommandContainer; +import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.part.SubCommandPart; + +import java.util.List; + +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; +import static com.sk89q.worldedit.internal.command.CommandUtil.requireIV; + +/** + * Extracted from {@link SelectionCommands} to allow importing of {@link Command}. + */ +@CommandContainer +public class ExpandCommands { + + public static void register(CommandRegistrationHandler registration, + CommandManager commandManager, + CommandManagerService commandManagerService) { + // Collect the general expand command + CommandManager collect = commandManagerService.newCommandManager(); + + registration.register( + collect, + ExpandCommandsRegistration.builder(), + new ExpandCommands() + ); + + Command expandBaseCommand = collect.getCommand("/expand") + .orElseThrow(() -> new IllegalStateException("No /expand command")); + + commandManager.register("/expand", command -> { + command.condition(new PermissionCondition(ImmutableSet.of("worldedit.selection.expand"))); + + command.addPart(SubCommandPart.builder( + TranslatableComponent.of("vert"), + TextComponent.of("Vertical expansion sub-command") + ) + .withCommands(ImmutableSet.of(createVertCommand(commandManager))) + .optional() + .build()); + + command.addParts(expandBaseCommand.getParts()); + command.action(expandBaseCommand.getAction()); + command.description(expandBaseCommand.getDescription()); + }); + } + + private static Command createVertCommand(CommandManager commandManager) { + return commandManager.newCommand("vert") + .description(TextComponent.of("Vertically expand the selection to world limits.")) + .action(parameters -> { + expandVert( + requireIV(Key.of(LocalSession.class), "localSession", parameters), + requireIV(Key.of(Player.class), "localSession", parameters) + ); + return 1; + }) + .build(); + } + + private static void expandVert(LocalSession session, Player player) throws IncompleteRegionException { + Region region = session.getSelection(player.getWorld()); + try { + int oldSize = region.getArea(); + region.expand( + BlockVector3.at(0, (player.getWorld().getMaxY() + 1), 0), + BlockVector3.at(0, -(player.getWorld().getMaxY() + 1), 0)); + session.getRegionSelector(player.getWorld()).learnChanges(); + int newSize = region.getArea(); + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + player.print("Region expanded " + (newSize - oldSize) + + " blocks [top-to-bottom]."); + } catch (RegionOperationException e) { + player.printError(e.getMessage()); + } + } + + @org.enginehub.piston.annotation.Command( + name = "/expand", + desc = "Expand the selection area" + ) + @Logging(REGION) + public void expand(Player player, LocalSession session, + @Arg(desc = "Amount to expand the selection by, can be `vert` to expand to the whole vertical column") + int amount, + @Arg(desc = "Amount to expand the selection by in the other direction", def = "0") + int reverseAmount, + @Arg(desc = "Direction to expand", def = Direction.AIM) + @MultiDirection + List direction) throws WorldEditException { + Region region = session.getSelection(player.getWorld()); + int oldSize = region.getArea(); + + if (reverseAmount == 0) { + for (BlockVector3 dir : direction) { + region.expand(dir.multiply(amount)); + } + } else { + for (BlockVector3 dir : direction) { + region.expand(dir.multiply(amount), dir.multiply(-reverseAmount)); + } + } + + session.getRegionSelector(player.getWorld()).learnChanges(); + int newSize = region.getArea(); + + session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + + player.print("Region expanded " + (newSize - oldSize) + " block(s)."); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index bac02819a..155385c52 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -24,7 +24,6 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.command.argument.ExpandAmount; import com.sk89q.worldedit.command.argument.SelectorChoice; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; @@ -267,63 +266,6 @@ public class SelectionCommands { } } - @Command( - name = "/expand", - desc = "Expand the selection area" - ) - @Logging(REGION) - @CommandPermissions("worldedit.selection.expand") - public void expand(Player player, LocalSession session, - @Arg(desc = "Amount to expand the selection by, can be `vert` to expand to the whole vertical column") - ExpandAmount amount, - @Arg(desc = "Amount to expand the selection by in the other direction", def = "0") - int reverseAmount, - @Arg(desc = "Direction to expand", def = Direction.AIM) - @MultiDirection - List direction) throws WorldEditException { - - // Special syntax (//expand vert) to expand the selection between - // sky and bedrock. - if (amount.isVert()) { - Region region = session.getSelection(player.getWorld()); - try { - int oldSize = region.getArea(); - region.expand( - BlockVector3.at(0, (player.getWorld().getMaxY() + 1), 0), - BlockVector3.at(0, -(player.getWorld().getMaxY() + 1), 0)); - session.getRegionSelector(player.getWorld()).learnChanges(); - int newSize = region.getArea(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - player.print("Region expanded " + (newSize - oldSize) - + " blocks [top-to-bottom]."); - } catch (RegionOperationException e) { - player.printError(e.getMessage()); - } - - return; - } - - Region region = session.getSelection(player.getWorld()); - int oldSize = region.getArea(); - - if (reverseAmount == 0) { - for (BlockVector3 dir : direction) { - region.expand(dir.multiply(amount.getAmount())); - } - } else { - for (BlockVector3 dir : direction) { - region.expand(dir.multiply(amount.getAmount()), dir.multiply(-reverseAmount)); - } - } - - session.getRegionSelector(player.getWorld()).learnChanges(); - int newSize = region.getArea(); - - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - - player.print("Region expanded " + (newSize - oldSize) + " block(s)."); - } - @Command( name = "/contract", desc = "Contract the selection area" diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index af59e5adc..3b6217154 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -515,11 +515,13 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.help") public void help(Actor actor, + @Switch(name = 's', desc = "List sub-commands of the given command, if applicable") + boolean listSubCommands, @Arg(desc = "The page to retrieve", def = "1") int page, @Arg(desc = "The command to retrieve help for", def = "", variable = true) List command) throws WorldEditException { - PrintCommandHelp.help(command, page, we, actor); + PrintCommandHelp.help(command, page, listSubCommands, we, actor); } } 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 154f57f52..1a383a767 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 @@ -157,10 +157,12 @@ public class WorldEditCommands { ) @CommandPermissions("worldedit.help") public void help(Actor actor, + @Switch(name = 's', desc = "List sub-commands of the given command, if applicable") + boolean listSubCommands, @Arg(desc = "The page to retrieve", def = "1") int page, @Arg(desc = "The command to retrieve help for", def = "", variable = true) List command) throws WorldEditException { - PrintCommandHelp.help(command, page, we, actor); + PrintCommandHelp.help(command, page, listSubCommands, we, actor); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java deleted file mode 100644 index 062a330c9..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmount.java +++ /dev/null @@ -1,51 +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 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.command.argument; - -import javax.annotation.Nullable; - -import static com.google.common.base.Preconditions.checkNotNull; - -public final class ExpandAmount { - - public static ExpandAmount vert() { - return new ExpandAmount(null); - } - - public static ExpandAmount from(int amount) { - return new ExpandAmount(amount); - } - - @Nullable - private final Integer amount; - - private ExpandAmount(@Nullable Integer amount) { - this.amount = amount; - } - - public boolean isVert() { - return amount == null; - } - - public int getAmount() { - return checkNotNull(amount, "This amount is vertical, i.e. undefined"); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java deleted file mode 100644 index b54311bee..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/ExpandAmountConverter.java +++ /dev/null @@ -1,70 +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 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.command.argument; - -import com.google.common.reflect.TypeToken; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import org.enginehub.piston.CommandManager; -import org.enginehub.piston.converter.ArgumentConverter; -import org.enginehub.piston.converter.ArgumentConverters; -import org.enginehub.piston.converter.ConversionResult; -import org.enginehub.piston.converter.SuccessfulConversion; -import org.enginehub.piston.inject.InjectedValueAccess; -import org.enginehub.piston.inject.Key; - -import java.util.List; -import java.util.stream.Stream; - -import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; - -public class ExpandAmountConverter implements ArgumentConverter { - - public static void register(CommandManager commandManager) { - commandManager.registerConverter(Key.of(ExpandAmount.class), new ExpandAmountConverter()); - } - - private final ArgumentConverter integerConverter = - ArgumentConverters.get(TypeToken.of(int.class)); - - private ExpandAmountConverter() { - } - - @Override - public Component describeAcceptableArguments() { - return TextComponent.of("`vert` or ").append(integerConverter.describeAcceptableArguments()); - } - - @Override - public List getSuggestions(String input) { - return limitByPrefix(Stream.concat( - Stream.of("vert"), integerConverter.getSuggestions(input).stream() - ), input); - } - - @Override - public ConversionResult convert(String argument, InjectedValueAccess context) { - if (argument.equalsIgnoreCase("vert") - || argument.equalsIgnoreCase("vertical")) { - return SuccessfulConversion.fromSingle(ExpandAmount.vert()); - } - return integerConverter.convert(argument, context).mapSingle(ExpandAmount::from); - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java index f79d3bdd1..d2f70a006 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java @@ -17,7 +17,6 @@ * along with this program. If not, see . */ - package com.sk89q.worldedit.command.util; import com.google.common.base.Strings; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java index aa911b705..ab21a39b9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.command.util; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.util.formatting.component.CommandListBox; @@ -66,7 +67,7 @@ public class PrintCommandHelp { return mapping.orElse(null); } - public static void help(List commandPath, int page, WorldEdit we, Actor actor) throws InvalidComponentException { + public static void help(List commandPath, int page, boolean listSubCommands, WorldEdit we, Actor actor) throws InvalidComponentException { CommandManager manager = we.getPlatformManager().getPlatformCommandManager().getCommandManager(); if (commandPath.isEmpty()) { @@ -89,7 +90,7 @@ public class PrintCommandHelp { if (subCommands.isEmpty()) { actor.printError(String.format("'%s' has no sub-commands. (Maybe '%s' is for a parameter?)", - Joiner.on(" ").join(visited.stream().map(Command::getName).iterator()), subCommand)); + toCommandString(visited), subCommand)); // full help for single command CommandUsageBox box = new CommandUsageBox(visited, visited.stream() .map(Command::getName).collect(Collectors.joining(" "))); @@ -102,27 +103,28 @@ public class PrintCommandHelp { visited.add(currentCommand); } else { actor.printError(String.format("The sub-command '%s' under '%s' could not be found.", - subCommand, Joiner.on(" ").join(visited.stream().map(Command::getName).iterator()))); + subCommand, toCommandString(visited))); // list subcommands for currentCommand - CommandUsageBox box = new CommandUsageBox(visited, visited.stream() - .map(Command::getName).collect(Collectors.joining(" "))); - actor.print(box.create()); + printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited); return; } } Map subCommands = getSubCommands(currentCommand); - if (subCommands.isEmpty()) { + if (subCommands.isEmpty() || !listSubCommands) { // Create the message - CommandUsageBox box = new CommandUsageBox(visited, visited.stream() - .map(Command::getName).collect(Collectors.joining(" "))); + CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited)); actor.print(box.create()); } else { printCommands(page, subCommands.values().stream(), actor, visited); } } + private static String toCommandString(List visited) { + return "/" + Joiner.on(" ").join(visited.stream().map(Command::getName).iterator()); + } + private static void printCommands(int page, Stream commandStream, Actor actor, List commandList) throws InvalidComponentException { // Get a list of aliases @@ -130,11 +132,10 @@ public class PrintCommandHelp { .sorted(byCleanName()) .collect(toList()); - String used = commandList.isEmpty() ? null - : Joiner.on(" ").join(commandList.stream().map(Command::getName).iterator()); + String used = commandList.isEmpty() ? null : toCommandString(commandList); CommandListBox box = new CommandListBox( (used == null ? "Help" : "Subcommands: " + used), - "//help %page%" + (used == null ? "" : " " + used)); + "//help -s %page%" + (used == null ? "" : " " + used)); if (!actor.isPlayer()) { box.formatForConsole(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 455ae0403..8708de678 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -36,6 +36,7 @@ import com.sk89q.worldedit.command.ChunkCommands; import com.sk89q.worldedit.command.ChunkCommandsRegistration; import com.sk89q.worldedit.command.ClipboardCommands; import com.sk89q.worldedit.command.ClipboardCommandsRegistration; +import com.sk89q.worldedit.command.ExpandCommands; import com.sk89q.worldedit.command.GeneralCommands; import com.sk89q.worldedit.command.GeneralCommandsRegistration; import com.sk89q.worldedit.command.GenerationCommands; @@ -73,7 +74,6 @@ import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; import com.sk89q.worldedit.command.argument.DirectionConverter; import com.sk89q.worldedit.command.argument.EntityRemoverConverter; import com.sk89q.worldedit.command.argument.EnumConverter; -import com.sk89q.worldedit.command.argument.ExpandAmountConverter; import com.sk89q.worldedit.command.argument.FactoryConverter; import com.sk89q.worldedit.command.argument.RegionFactoryConverter; import com.sk89q.worldedit.command.argument.RegistryConverter; @@ -104,6 +104,7 @@ import com.sk89q.worldedit.world.World; import org.enginehub.piston.ColorConfig; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; +import org.enginehub.piston.TextConfig; import org.enginehub.piston.converter.ArgumentConverters; import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.CommandExecutionException; @@ -148,6 +149,10 @@ public final class PlatformCommandManager { private static final java.util.logging.Logger COMMAND_LOG = java.util.logging.Logger.getLogger("com.sk89q.worldedit.CommandLog"); + static { + TextConfig.setCommandPrefix("/"); + } + private final WorldEdit worldEdit; private final PlatformManager platformManager; private final CommandManagerServiceImpl commandManagerService; @@ -206,7 +211,6 @@ public final class PlatformCommandManager { VectorConverter.register(commandManager); EnumConverter.register(commandManager); RegistryConverter.register(commandManager); - ExpandAmountConverter.register(commandManager); ZonedDateTimeConverter.register(commandManager); BooleanConverter.register(commandManager); EntityRemoverConverter.register(commandManager); @@ -360,6 +364,7 @@ public final class PlatformCommandManager { SelectionCommandsRegistration.builder(), new SelectionCommands(worldEdit) ); + ExpandCommands.register(registration, commandManager, commandManagerService); this.registration.register( commandManager, SnapshotUtilCommandsRegistration.builder(), diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java index e3032fa95..b98236090 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java @@ -27,6 +27,8 @@ import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import org.enginehub.piston.Command; import org.enginehub.piston.exception.CommandException; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; import org.enginehub.piston.part.SubCommandPart; import java.util.Comparator; @@ -120,6 +122,12 @@ public class CommandUtil { } } + public static T requireIV(Key type, String name, InjectedValueAccess injectedValueAccess) { + return injectedValueAccess.injectedValue(type).orElseThrow(() -> + new IllegalStateException("No injected value for " + name + " (type " + type + ")") + ); + } + private CommandUtil() { } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java index 5351ed36b..c5161bd90 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/Keyed.java @@ -17,7 +17,6 @@ * along with this program. If not, see . */ - package com.sk89q.worldedit.registry; /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index 46347d107..e8abe0e38 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -20,17 +20,19 @@ package com.sk89q.worldedit.util.formatting.component; import com.google.common.collect.Iterables; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; +import com.sk89q.worldedit.util.formatting.text.format.TextDecoration; +import org.enginehub.piston.ColorConfig; import org.enginehub.piston.Command; import org.enginehub.piston.CommandParameters; import org.enginehub.piston.util.HelpGenerator; import javax.annotation.Nullable; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.internal.command.CommandUtil.byCleanName; import static com.sk89q.worldedit.internal.command.CommandUtil.getSubCommands; /** @@ -58,35 +60,26 @@ public class CommandUsageBox extends TextComponentProducer { public CommandUsageBox(List commands, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException { checkNotNull(commands); checkNotNull(commandString); - Map subCommands = getSubCommands(Iterables.getLast(commands)); - if (subCommands.isEmpty()) { - attachCommandUsage(commands, commandString); - } else { - attachSubcommandUsage(subCommands, commandString, parameters); - } - } - - private void attachSubcommandUsage(Map dispatcher, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException { - CommandListBox box = new CommandListBox(commandString.isEmpty() ? "Help" : "Subcommands:" + commandString, - "//help %page%" + (commandString.isEmpty() ? "" : " " + commandString)); - String prefix = !commandString.isEmpty() ? commandString + " " : ""; - - List list = dispatcher.values().stream() - .sorted(byCleanName()) - .collect(Collectors.toList()); - - for (Command mapping : list) { - if (parameters == null || mapping.getCondition().satisfied(parameters)) { - box.appendCommand(prefix + mapping.getName(), mapping.getDescription()); - } - } - - append(box.create(1)); + attachCommandUsage(commands, commandString); } private void attachCommandUsage(List commands, String commandString) { + TextComponentProducer boxContent = new TextComponentProducer() + .append(HelpGenerator.create(commands).getFullHelp()); + if (getSubCommands(Iterables.getLast(commands)).size() > 0) { + boxContent.append(TextComponent.newline()) + .append(TextComponent.builder("> ") + .color(ColorConfig.getHelpText()) + .append(TextComponent.builder("List Subcommands") + .color(ColorConfig.getMainText()) + .decoration(TextDecoration.ITALIC, true) + .clickEvent(ClickEvent.runCommand("//help -s " + commandString)) + .hoverEvent(HoverEvent.showText(TextComponent.of("List all subcommands of this command"))) + .build()) + .build()); + } MessageBox box = new MessageBox("Help for " + commandString, - new TextComponentProducer().append(HelpGenerator.create(commands).getFullHelp())); + boxContent); append(box.create()); } diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index ef2c30446..a1954e09d 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -91,7 +91,7 @@ configure(subprojects + project("core:ap")) { def textExtrasVersion = "3.0.2" project("core") { def textVersion = "3.0.0" - def pistonVersion = '0.2.4' + def pistonVersion = '0.3.0' dependencies { shade "net.kyori:text-api:$textVersion" From 334d5cfaabefcf8d7dd802eea8bcc29e1d18b4e3 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 18 May 2019 09:52:24 -0400 Subject: [PATCH 143/366] The "spawner|mobType" syntax once again makes functional mob spawners. Also fix block parser context not being restricted. --- .../bukkit/BukkitServerInterface.java | 5 +- .../worldedit/blocks/MobSpawnerBlock.java | 58 +++++++++++-------- .../command/argument/FactoryConverter.java | 1 + .../factory/parser/DefaultBlockParser.java | 11 ++-- .../extension/platform/Platform.java | 2 +- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index e4707341a..ccc025d8c 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -86,7 +86,10 @@ public class BukkitServerInterface implements MultiUserPlatform { @Override public boolean isValidMobType(String type) { - final EntityType entityType = EntityType.fromName(type); + if (!type.startsWith("minecraft:")) { + return false; + } + final EntityType entityType = EntityType.fromName(type.substring(10)); return entityType != null && entityType.isAlive(); } diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java index eb0c2e382..cde191e64 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java @@ -19,7 +19,10 @@ package com.sk89q.worldedit.blocks; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.NBTUtils; import com.sk89q.jnbt.ShortTag; @@ -38,17 +41,17 @@ import java.util.Map; public class MobSpawnerBlock extends BaseBlock { private String mobType; - private short delay; + private short delay = -1; // advanced mob spawner features - private short spawnCount; - private short spawnRange; + private short spawnCount = 4; + private short spawnRange = 4; private CompoundTag spawnData; private ListTag spawnPotentials; - private short minSpawnDelay; - private short maxSpawnDelay; - private short maxNearbyEntities; - private short requiredPlayerRange; + private short minSpawnDelay = 200; + private short maxSpawnDelay = 800; + private short maxNearbyEntities = 6; + private short requiredPlayerRange = 16; /** * Construct the mob spawner block with a specified data value. @@ -119,7 +122,6 @@ public class MobSpawnerBlock extends BaseBlock { @Override public CompoundTag getNbtData() { Map values = new HashMap<>(); - values.put("EntityId", new StringTag(mobType)); values.put("Delay", new ShortTag(delay)); values.put("SpawnCount", new ShortTag(spawnCount)); values.put("SpawnRange", new ShortTag(spawnRange)); @@ -127,10 +129,16 @@ public class MobSpawnerBlock extends BaseBlock { values.put("MaxSpawnDelay", new ShortTag(maxSpawnDelay)); values.put("MaxNearbyEntities", new ShortTag(maxNearbyEntities)); values.put("RequiredPlayerRange", new ShortTag(requiredPlayerRange)); - if (spawnData != null) { + if (spawnData == null) { + values.put("SpawnData", new CompoundTag(ImmutableMap.of("id", new StringTag(mobType)))); + } else { values.put("SpawnData", new CompoundTag(spawnData.getValue())); } - if (spawnPotentials != null) { + if (spawnPotentials == null) { + values.put("SpawnPotentials", new ListTag(CompoundTag.class, ImmutableList.of( + new CompoundTag(ImmutableMap.of("Weight", new IntTag(1), "Entity", + new CompoundTag(ImmutableMap.of("id", new StringTag(mobType)))))))); + } else { values.put("SpawnPotentials", new ListTag(CompoundTag.class, spawnPotentials.getValue())); } @@ -150,18 +158,26 @@ public class MobSpawnerBlock extends BaseBlock { throw new RuntimeException("'MobSpawner' tile entity expected"); } - StringTag mobTypeTag; + CompoundTag spawnDataTag; + String mobType; ShortTag delayTag; try { - mobTypeTag = NBTUtils.getChildTag(values, "EntityId", StringTag.class); - delayTag = NBTUtils.getChildTag(values, "Delay", ShortTag.class); + spawnDataTag = NBTUtils.getChildTag(values, "SpawnData", CompoundTag.class); + mobType = spawnDataTag.getString("id"); + if (mobType.equals("")) { + throw new InvalidFormatException("No spawn id."); + } + this.mobType = mobType; } catch (InvalidFormatException ignored) { - throw new RuntimeException("Invalid mob spawner data: no EntityId and/or no Delay"); + throw new RuntimeException("Invalid mob spawner data: no SpawnData and/or no Delay"); + } + try { + delayTag = NBTUtils.getChildTag(values, "Delay", ShortTag.class); + this.delay = delayTag.getValue(); + } catch (InvalidFormatException ignored) { + this.delay = -1; } - - this.mobType = mobTypeTag.getValue(); - this.delay = delayTag.getValue(); ShortTag spawnCountTag = null; ShortTag spawnRangeTag = null; @@ -170,7 +186,6 @@ public class MobSpawnerBlock extends BaseBlock { ShortTag maxNearbyEntitiesTag = null; ShortTag requiredPlayerRangeTag = null; ListTag spawnPotentialsTag = null; - CompoundTag spawnDataTag = null; try { spawnCountTag = NBTUtils.getChildTag(values, "SpawnCount", ShortTag.class); } catch (InvalidFormatException ignored) { @@ -199,10 +214,6 @@ public class MobSpawnerBlock extends BaseBlock { spawnPotentialsTag = NBTUtils.getChildTag(values, "SpawnPotentials", ListTag.class); } catch (InvalidFormatException ignored) { } - try { - spawnDataTag = NBTUtils.getChildTag(values, "SpawnData", CompoundTag.class); - } catch (InvalidFormatException ignored) { - } if (spawnCountTag != null) { this.spawnCount = spawnCountTag.getValue(); @@ -225,9 +236,6 @@ public class MobSpawnerBlock extends BaseBlock { if (spawnPotentialsTag != null) { this.spawnPotentials = new ListTag(CompoundTag.class, spawnPotentialsTag.getValue()); } - if (spawnDataTag != null) { - this.spawnData = new CompoundTag(spawnDataTag.getValue()); - } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index 0de24e5a7..b3b2b8108 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -81,6 +81,7 @@ public class FactoryConverter implements ArgumentConverter { } } parserContext.setSession(session); + parserContext.setRestricted(true); try { return SuccessfulConversion.fromSingle( 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 a103318ef..f0a14bee7 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 @@ -46,6 +46,8 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.FuzzyBlockState; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; import java.util.HashMap; @@ -323,12 +325,11 @@ public class DefaultBlockParser extends InputParser { // Allow setting mob spawn type if (blockAndExtraData.length > 1) { String mobName = blockAndExtraData[1]; - for (MobType mobType : MobType.values()) { - if (mobType.getName().toLowerCase(Locale.ROOT).equals(mobName.toLowerCase(Locale.ROOT))) { - mobName = mobType.getName(); - break; - } + EntityType ent = EntityTypes.get(mobName.toLowerCase(Locale.ROOT)); + if (ent == null) { + throw new NoMatchException("Unknown entity type '" + mobName + "'"); } + mobName = ent.getId(); if (!worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).isValidMobType(mobName)) { throw new NoMatchException("Unknown mob type '" + mobName + "'"); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index d9391ddc3..fcbd6ff29 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -63,7 +63,7 @@ public interface Platform { * Checks if a mob type is valid. * * @param type The mob type name to check - * @return Whether the name is a valid mod bype + * @return Whether the name is a valid mod type */ boolean isValidMobType(String type); From 8ee484fca8d05818c4896bfea3b1dc5c29f3c3b3 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sun, 19 May 2019 13:34:43 +1000 Subject: [PATCH 144/366] Removed unused classes --- .../sk89q/worldedit/blocks/ClothColor.java | 100 ------------------ .../worldedit/blocks/metadata/MobType.java | 66 ------------ .../factory/parser/DefaultBlockParser.java | 3 +- 3 files changed, 1 insertion(+), 168 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/blocks/metadata/MobType.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java deleted file mode 100644 index 64719c113..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/ClothColor.java +++ /dev/null @@ -1,100 +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 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.blocks; - -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -import javax.annotation.Nullable; - -/** - * The colors for wool. - * - *

    This class may be removed in the future.

    - */ -public enum ClothColor { - - WHITE("White", "white"), - ORANGE("Orange", "orange"), - MAGENTA("Magenta", "magenta"), - LIGHT_BLUE("Light blue", "lightblue"), - YELLOW("Yellow", "yellow"), - LIGHT_GREEN("Light green", "lightgreen"), - PINK("Pink", "pink", "lightred"), - GRAY("Gray", "grey", "gray"), - LIGHT_GRAY("Light gray", "lightgrey", "lightgray"), - CYAN("Cyan", "cyan", "turquoise"), - PURPLE("Purple", "purple", "violet"), - BLUE("Blue", "blue"), - BROWN("Brown", "brown", "cocoa", "coffee"), - DARK_GREEN("Dark green", "green", "darkgreen", "cactusgreen", "cactigreen"), - RED("Red", "red"), - BLACK("Black", "black"); - /** - * Stores a map of the names for fast access. - */ - private static final Map lookup = new HashMap<>(); - - private final String name; - private final String[] lookupKeys; - - static { - for (ClothColor type : EnumSet.allOf(ClothColor.class)) { - for (String key : type.lookupKeys) { - lookup.put(key, type); - } - } - } - - - /** - * Construct the type. - * - * @param name the name of the color - * @param lookupKeys a name to refer to the color by - */ - ClothColor(String name, String ... lookupKeys) { - this.name = name; - this.lookupKeys = lookupKeys; - } - - /** - * Return type from name. May return null. - * - * @param name the name of the color - * @return a color or null - */ - @Nullable - public static ClothColor lookup(String name) { - return lookup.get(name.toLowerCase(Locale.ROOT)); - } - - /** - * Get user-friendly item name. - * - * @return the name - */ - public String getName() { - return name; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/metadata/MobType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/metadata/MobType.java deleted file mode 100644 index 762f39715..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/blocks/metadata/MobType.java +++ /dev/null @@ -1,66 +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 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.blocks.metadata; - -/** - * Represents the possible types of mobs. - */ -public enum MobType { - BAT("Bat"), - BLAZE("Blaze"), - CAVE_SPIDER("CaveSpider"), - CHICKEN("Chicken"), - COW("Cow"), - CREEPER("Creeper"), - ENDERDRAGON("EnderDragon"), - ENDERMAN("Enderman"), - GHAST("Ghast"), - GIANT("Giant"), - VILLAGER_GOLEM("VillagerGolem"), - HORSE("EntityHorse"), - MAGMA_CUBE("LavaSlime"), - MOOSHROOM("MushroomCow"), - OCELOT("Ozelot"), - PIG("Pig"), - PIG_ZOMBIE("PigZombie"), - SHEEP("Sheep"), - SILVERFISH("Silverfish"), - SKELETON("Skeleton"), - SLIME("Slime"), - SNOWMAN("SnowMan"), - SPIDER("Spider"), - SQUID("Squid"), - VILLAGER("Villager"), - WITCH("Witch"), - WITHER("WitherBoss"), - WOLF("Wolf"), - ZOMBIE("Zombie"); - - private final String name; - - MobType(String name) { - this.name = name; - } - - public String getName() { - return name; - } - -} 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 f0a14bee7..d2212a40e 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 @@ -27,7 +27,6 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.MobSpawnerBlock; import com.sk89q.worldedit.blocks.SignBlock; import com.sk89q.worldedit.blocks.SkullBlock; -import com.sk89q.worldedit.blocks.metadata.MobType; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.input.InputParseException; @@ -335,7 +334,7 @@ public class DefaultBlockParser extends InputParser { } return new MobSpawnerBlock(state, mobName); } else { - return new MobSpawnerBlock(state, MobType.PIG.getName()); + return new MobSpawnerBlock(state, EntityTypes.PIG.getId()); } } else if (blockType == BlockTypes.PLAYER_HEAD || blockType == BlockTypes.PLAYER_WALL_HEAD) { // allow setting type/player/rotation From b0777f6b062112ee6b8bb617c61588fee358d76a Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 16 May 2019 00:00:31 -0400 Subject: [PATCH 145/366] Use DFUs for some additional data fixing. Legacy mapper now uses the data fixers to upgrade blocks and item types (e.g. signs, dyes that changed names in 1.14). The sponge schematic reader can now attempt to use the data fixers to upgrade blocks, block entities, biomes and entities. This has been tested with the 1.13 -> 1.14 changes. It is yet to be seen if it will continue to work because... The mc edit schematic reader has code for using data fixers, but it is currently disabled as there seem to be some issues with fixing up older block entities. --- .../worldedit/bukkit/WorldEditPlugin.java | 33 +++-- .../src/main/resources/plugin.yml | 1 + .../src/main/resources/worldedit-adapters.jar | Bin 444681 -> 450923 bytes .../clipboard/io/MCEditSchematicReader.java | 114 +++++++++++------- .../clipboard/io/SpongeSchematicReader.java | 79 +++++++----- .../FlowerPotCompatibilityHandler.java | 1 + .../NoteBlockCompatibilityHandler.java | 3 +- .../com/sk89q/worldedit/world/DataFixer.java | 29 ++++- .../worldedit/world/chunk/AnvilChunk13.java | 31 +---- .../world/registry/LegacyMapper.java | 66 ++++++---- .../registry/PassthroughBlockMaterial.java | 2 +- .../worldedit/world/storage/ChunkStore.java | 3 +- 12 files changed, 220 insertions(+), 142 deletions(-) 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 11fc7de09..3c147456c 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 @@ -58,6 +58,10 @@ import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.world.WorldInitEvent; import org.bukkit.plugin.java.JavaPlugin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -102,11 +106,6 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // Setup platform server = new BukkitServerInterface(this, getServer()); worldEdit.getPlatformManager().register(server); - loadAdapter(); // Need an adapter to work with special blocks with NBT data - setupRegistries(); - worldEdit.loadMappings(); - - loadConfig(); // Load configuration } /** @@ -114,8 +113,6 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { */ @Override public void onEnable() { - setupTags(); // these have to be done post-world since they rely on MC registries. the other ones just use Bukkit enums - PermissionsResolverManager.initialize(this); // Setup permission resolver // Register CUI @@ -125,10 +122,8 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // Now we can register events getServer().getPluginManager().registerEvents(new WorldEditListener(this), this); - // If we are on MCPC+/Cauldron, then Forge will have already loaded - // Forge WorldEdit and there's (probably) not going to be any other - // platforms to be worried about... at the current time of writing - WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + // register this so we can load world-dependent data right as the first world is loading + getServer().getPluginManager().registerEvents(new WorldInitListener(), this); // Enable metrics new Metrics(this); @@ -433,4 +428,20 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { return bukkitAdapter; } + private class WorldInitListener implements Listener { + private boolean loaded = false; + @EventHandler(priority = EventPriority.LOWEST) + public void onWorldInit(@SuppressWarnings("unused") WorldInitEvent event) { + if (loaded) return; + loaded = true; + + loadAdapter(); // Need an adapter to work with special blocks with NBT data + setupRegistries(); + WorldEdit.getInstance().loadMappings(); + loadConfig(); // Load configuration + setupTags(); + + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + } + } } diff --git a/worldedit-bukkit/src/main/resources/plugin.yml b/worldedit-bukkit/src/main/resources/plugin.yml index e64d26bdc..27808257f 100644 --- a/worldedit-bukkit/src/main/resources/plugin.yml +++ b/worldedit-bukkit/src/main/resources/plugin.yml @@ -1,6 +1,7 @@ name: WorldEdit main: com.sk89q.worldedit.bukkit.WorldEditPlugin version: "${internalVersion}" +load: STARTUP api-version: 1.13 # Permissions aren't here. Read http://wiki.sk89q.com/wiki/WEPIF/DinnerPerms diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index 4c6d73becaa46168071b760d0d3b5670d291f3a2..74ff20abd745b653bdb0c60e4b536fb9b3ad1364 100644 GIT binary patch delta 293138 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 z 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

    Uh|C99>_aWv_|SmUkxqjjHo*!d4X?Yjx+^R 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 J+z4U*{6F2>r)&TK delta 287033 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

    RAcHyQblaYSwnIQ@56DetUlWXz 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%0Ax<6Eo;g-EoTkd%GDWK4nT+dir+ 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 O$+!ivmjO36ul*lnX$h(T 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 dc99d66dc..bcba783a4 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 @@ -44,6 +44,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityTypes; @@ -67,21 +68,20 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class MCEditSchematicReader extends NBTSchematicReader { - private static final ImmutableList COMPATIBILITY_HANDLERS - = ImmutableList.of( - new SignCompatibilityHandler(), - new FlowerPotCompatibilityHandler(), - new NoteBlockCompatibilityHandler(), - new SkullBlockCompatibilityHandler() - // TODO - item tags for inventories...? DFUs :> - ); - private static final ImmutableList ENTITY_COMPATIBILITY_HANDLERS - = ImmutableList.of( - new Pre13HangingCompatibilityHandler() - ); - 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() + ); + private static final ImmutableList ENTITY_COMPATIBILITY_HANDLERS + = ImmutableList.of( + new Pre13HangingCompatibilityHandler() + ); /** * Create a new instance. @@ -91,6 +91,9 @@ public class MCEditSchematicReader extends NBTSchematicReader { public MCEditSchematicReader(NBTInputStream inputStream) { checkNotNull(inputStream); this.inputStream = inputStream; + this.fixer = null; + //com.sk89q.worldedit.WorldEdit.getInstance().getPlatformManager().queryCapability( + //com.sk89q.worldedit.extension.platform.Capability.WORLD_EDITING).getDataFixer(); } @Override @@ -176,39 +179,44 @@ public class MCEditSchematicReader extends NBTSchematicReader { // Need to pull out tile entities List tileEntities = requireTag(schematic, "TileEntities", ListTag.class).getValue(); Map> tileEntitiesMap = new HashMap<>(); - Map blockOverrides = new HashMap<>(); + Map blockStates = new HashMap<>(); for (Tag tag : tileEntities) { if (!(tag instanceof CompoundTag)) continue; CompoundTag t = (CompoundTag) tag; - + Map values = new HashMap<>(t.getValue()); + String id = t.getString("id"); + values.put("id", new StringTag(convertBlockEntityId(id))); int x = t.getInt("x"); int y = t.getInt("y"); int z = t.getInt("z"); - String id = t.getString("id"); - - Map values = new HashMap<>(t.getValue()); - values.put("id", new StringTag(convertBlockEntityId(id))); - int index = y * width * length + z * width + x; - BlockState block = LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]); + + BlockState block = getBlockState(blocks[index], blockData[index]); BlockState newBlock = block; if (newBlock != null) { for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { if (handler.isAffectedBlock(newBlock)) { newBlock = handler.updateNBT(block, values); - if (newBlock == null) { + if (newBlock == null || values.isEmpty()) { break; } } } } + if (values.isEmpty()) { + t = null; + } + + if (fixer != null && t != null) { + t = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, t, -1); + } BlockVector3 vec = BlockVector3.at(x, y, z); - tileEntitiesMap.put(vec, values); - if (newBlock != block) { - blockOverrides.put(vec, newBlock); + if (t != null) { + tileEntitiesMap.put(vec, t.getValue()); } + blockStates.put(vec, newBlock); } BlockArrayClipboard clipboard = new BlockArrayClipboard(region); @@ -221,10 +229,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { for (int z = 0; z < length; ++z) { int index = y * width * length + z * width + x; BlockVector3 pt = BlockVector3.at(x, y, z); - boolean useOverride = blockOverrides.containsKey(pt); - BlockState state = useOverride - ? blockOverrides.get(pt) - : LegacyMapper.getInstance().getBlockFromLegacy(blocks[index], blockData[index]); + BlockState state = blockStates.computeIfAbsent(pt, p -> getBlockState(blocks[index], blockData[index])); try { if (state != null) { @@ -233,7 +238,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { } else { clipboard.setBlock(region.getMinimumPoint().add(pt), state); } - } else if (!useOverride) { + } else { short block = blocks[index]; byte data = blockData[index]; int combined = block << 8 | data; @@ -258,9 +263,11 @@ public class MCEditSchematicReader extends NBTSchematicReader { for (Tag tag : entityTags) { if (tag instanceof CompoundTag) { CompoundTag compound = (CompoundTag) tag; + if (fixer != null) { + compound = fixer.fixUp(DataFixer.FixTypes.ENTITY, compound, -1); + } String id = convertEntityId(compound.getString("id")); Location location = NBTConversions.toLocation(clipboard, compound.getListTag("Pos"), compound.getListTag("Rotation")); - if (!id.isEmpty()) { EntityType entityType = EntityTypes.get(id.toLowerCase(Locale.ROOT)); if (entityType != null) { @@ -343,26 +350,43 @@ public class MCEditSchematicReader extends NBTSchematicReader { } private String convertBlockEntityId(String id) { - switch(id) { - case "Cauldron": return "brewing_stand"; - case "Control": return "command_block"; - case "DLDetector": return "daylight_detector"; - case "Trap": return "dispenser"; - case "EnchantTable": return "enchanting_table"; - case "EndGateway": return "end_gateway"; - case "AirPortal": return "end_portal"; - case "EnderChest": return "ender_chest"; - case "FlowerPot": return "flower_pot"; - case "RecordPlayer": return "jukebox"; - case "MobSpawner": return "mob_spawner"; + switch (id) { + case "Cauldron": + return "brewing_stand"; + case "Control": + return "command_block"; + case "DLDetector": + return "daylight_detector"; + case "Trap": + return "dispenser"; + case "EnchantTable": + return "enchanting_table"; + case "EndGateway": + return "end_gateway"; + case "AirPortal": + return "end_portal"; + case "EnderChest": + return "ender_chest"; + case "FlowerPot": + return "flower_pot"; + case "RecordPlayer": + return "jukebox"; + case "MobSpawner": + return "mob_spawner"; case "Music": case "noteblock": return "note_block"; - case "Structure": return "structure_block"; - default: return id; + case "Structure": + return "structure_block"; + default: + return id; } } + private BlockState getBlockState(int id, int data) { + return LegacyMapper.getInstance().getBlockFromLegacy(id, data); + } + @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 d42d76afd..4a9362b6e 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 @@ -36,14 +36,15 @@ import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.io.legacycompat.NBTCompatibilityHandler; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; +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; @@ -54,7 +55,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -68,14 +68,10 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class SpongeSchematicReader extends NBTSchematicReader { - private static final List COMPATIBILITY_HANDLERS = new ArrayList<>(); - - static { - // If NBT Compat handlers are needed - add them here. - } - private static final Logger log = LoggerFactory.getLogger(SpongeSchematicReader.class); private final NBTInputStream inputStream; + private DataFixer fixer = null; + private int dataVersion = -1; /** * Create a new instance. @@ -97,17 +93,32 @@ public class SpongeSchematicReader extends NBTSchematicReader { // Check Map schematic = schematicTag.getValue(); + int version = requireTag(schematic, "Version", IntTag.class).getValue(); + final Platform platform = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.WORLD_EDITING); + int liveDataVersion = platform.getDataVersion(); + if (version == 1) { + dataVersion = 1631; // this is a relatively safe assumption unless someone imports a schematic from 1.12, e.g. sponge 7.1- + fixer = platform.getDataFixer(); return readVersion1(schematicTag); } else if (version == 2) { - int dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); - int liveDataVersion = WorldEdit.getInstance().getPlatformManager() - .queryCapability(Capability.WORLD_EDITING).getDataVersion(); + dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); if (dataVersion > liveDataVersion) { log.warn("Schematic was made in a newer Minecraft version ({} > {}). Data may be incompatible.", dataVersion, liveDataVersion); + } else if (dataVersion < liveDataVersion) { + fixer = platform.getDataFixer(); + if (fixer != null) { + log.info("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.", + dataVersion, liveDataVersion); + } else { + log.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.", + dataVersion, liveDataVersion); + } } + BlockArrayClipboard clip = readVersion1(schematicTag); return readVersion2(clip, schematicTag); } @@ -159,6 +170,9 @@ public class SpongeSchematicReader extends NBTSchematicReader { for (String palettePart : paletteObject.keySet()) { int id = requireTag(paletteObject, palettePart, IntTag.class).getValue(); + if (fixer != null) { + palettePart = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart, dataVersion); + } BlockState state; try { state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState(); @@ -184,7 +198,18 @@ public class SpongeSchematicReader extends NBTSchematicReader { for (Map tileEntity : tileEntityTags) { int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue(); - tileEntitiesMap.put(BlockVector3.at(pos[0], pos[1], pos[2]), tileEntity); + final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]); + if (fixer != null) { + Map values = Maps.newHashMap(tileEntity); + values.put("x", new IntTag(pt.getBlockX())); + values.put("y", new IntTag(pt.getBlockY())); + values.put("z", new IntTag(pt.getBlockZ())); + values.put("id", values.get("Id")); + values.remove("Id"); + values.remove("Pos"); + tileEntity = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values), dataVersion).getValue(); + } + tileEntitiesMap.put(pt, tileEntity); } } @@ -218,19 +243,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { BlockVector3 pt = BlockVector3.at(x, y, z); try { if (tileEntitiesMap.containsKey(pt)) { - Map values = Maps.newHashMap(tileEntitiesMap.get(pt)); - for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) { - if (handler.isAffectedBlock(state)) { - handler.updateNBT(state, values); - } - } - values.put("x", new IntTag(pt.getBlockX())); - values.put("y", new IntTag(pt.getBlockY())); - values.put("z", new IntTag(pt.getBlockZ())); - values.put("id", values.get("Id")); - values.remove("Id"); - values.remove("Pos"); - clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state.toBaseBlock(new CompoundTag(values))); + clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state.toBaseBlock(new CompoundTag(tileEntitiesMap.get(pt)))); } else { clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state); } @@ -267,9 +280,13 @@ public class SpongeSchematicReader extends NBTSchematicReader { Map paletteEntries = paletteTag.getValue(); for (Entry palettePart : paletteEntries.entrySet()) { - BiomeType biome = BiomeTypes.get(palettePart.getKey()); + String key = palettePart.getKey(); + if (fixer != null) { + key = fixer.fixUp(DataFixer.FixTypes.BIOME, key, dataVersion); + } + BiomeType biome = BiomeTypes.get(key); if (biome == null) { - log.warn("Unknown biome type :" + palettePart.getKey() + + 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(); @@ -322,14 +339,18 @@ public class SpongeSchematicReader extends NBTSchematicReader { CompoundTag entityTag = (CompoundTag) et; Map tags = entityTag.getValue(); String id = requireTag(tags, "Id", StringTag.class).getValue(); + entityTag = entityTag.createBuilder().putString("id", id).remove("Id").build(); + + if (fixer != null) { + entityTag = fixer.fixUp(DataFixer.FixTypes.ENTITY, entityTag, dataVersion); + } EntityType entityType = EntityTypes.get(id); if (entityType != null) { Location location = NBTConversions.toLocation(clipboard, requireTag(tags, "Pos", ListTag.class), requireTag(tags, "Rotation", ListTag.class)); - BaseEntity state = new BaseEntity(entityType, - entityTag.createBuilder().putString("id", id).remove("Id").build()); + BaseEntity state = new BaseEntity(entityType, entityTag); clipboard.createEntity(location, state); } else { log.warn("Unknown entity when pasting schematic: " + id); 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 225a9555e..df18a95da 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 @@ -48,6 +48,7 @@ public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { } BlockState newState = convertLegacyBlockType(id, data); if (newState != null) { + values.clear(); return (B) newState; // generics pls :\ } } 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 940086b8f..a839efe29 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 @@ -54,7 +54,8 @@ public class NoteBlockCompatibilityHandler implements NBTCompatibilityHandler { if (noteTag instanceof ByteTag) { Byte note = ((ByteTag) noteTag).getValue(); if (note != null) { - return block.with(NoteProperty, (int) note); + values.clear(); + return (B) block.with(NoteProperty, (int) note).toImmutableState(); } } return block; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java index 1318cf9c5..70182550d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/DataFixer.java @@ -22,13 +22,32 @@ package com.sk89q.worldedit.world; import com.google.common.annotations.Beta; import com.sk89q.jnbt.CompoundTag; +/** + * This entire class is subject to heavy changes. Do not use this as API. + */ @Beta public interface DataFixer { - /** - * API SUBJECT TO CHANGE. DON'T USE THIS. - */ - @Beta - CompoundTag fixChunk(CompoundTag originalChunk); + final class FixType { + private FixType() { + } + } + final class FixTypes { + private FixTypes() { + } + + public static FixType CHUNK = new FixType<>(); + public static FixType BLOCK_ENTITY = new FixType<>(); + public static FixType ENTITY = new FixType<>(); + public static FixType BLOCK_STATE = new FixType<>(); + public static FixType BIOME = new FixType<>(); + public static FixType ITEM_TYPE = new FixType<>(); + } + + default T fixUp(FixType type, T original) { + return fixUp(type, original, -1); + } + + T fixUp(FixType type, T original, int srcVer); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java index b9434ff0d..832fbf020 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -173,33 +173,10 @@ public class AnvilChunk13 implements Chunk { CompoundTag t = (CompoundTag) tag; - int x = 0; - int y = 0; - int z = 0; - - Map values = new HashMap<>(); - - for (Map.Entry entry : t.getValue().entrySet()) { - switch (entry.getKey()) { - case "x": - if (entry.getValue() instanceof IntTag) { - x = ((IntTag) entry.getValue()).getValue(); - } - break; - case "y": - if (entry.getValue() instanceof IntTag) { - y = ((IntTag) entry.getValue()).getValue(); - } - break; - case "z": - if (entry.getValue() instanceof IntTag) { - z = ((IntTag) entry.getValue()).getValue(); - } - break; - } - - values.put(entry.getKey(), entry.getValue()); - } + Map values = new HashMap<>(t.getValue()); + int x = ((IntTag) values.get("x")).getValue(); + int y = ((IntTag) values.get("y")).getValue(); + int z = ((IntTag) values.get("z")).getValue(); BlockVector3 vec = BlockVector3.at(x, y, z); tileEntities.put(vec, values); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java index 05acbeb1d..d12503f19 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java @@ -26,10 +26,13 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.gson.VectorAdapter; import com.sk89q.worldedit.util.io.ResourceLoader; +import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; @@ -41,18 +44,18 @@ import java.io.IOException; import java.net.URL; import java.nio.charset.Charset; import java.util.Arrays; +import java.util.HashMap; import java.util.Map; -import static com.google.common.base.Preconditions.checkNotNull; - -public class LegacyMapper { +public final class LegacyMapper { private static final Logger log = LoggerFactory.getLogger(LegacyMapper.class); private static LegacyMapper INSTANCE; - private Multimap stringToBlockMap = HashMultimap.create(); + private Map blockEntries = new HashMap<>(); + private Map stringToBlockMap = new HashMap<>(); private Multimap blockToStringMap = HashMultimap.create(); - private Multimap stringToItemMap = HashMultimap.create(); + private Map stringToItemMap = new HashMap<>(); private Multimap itemToStringMap = HashMultimap.create(); /** @@ -82,31 +85,50 @@ public class LegacyMapper { String data = Resources.toString(url, Charset.defaultCharset()); LegacyDataFile dataFile = gson.fromJson(data, new TypeToken() {}.getType()); + DataFixer fixer = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataFixer(); ParserContext parserContext = new ParserContext(); parserContext.setPreferringWildcard(false); parserContext.setRestricted(false); parserContext.setTryLegacy(false); // This is legacy. Don't match itself. for (Map.Entry blockEntry : dataFile.blocks.entrySet()) { + String id = blockEntry.getKey(); + blockEntries.put(id, blockEntry.getValue()); try { - String id = blockEntry.getKey(); BlockState state = WorldEdit.getInstance().getBlockFactory().parseFromInput(blockEntry.getValue(), parserContext).toImmutableState(); blockToStringMap.put(state, id); stringToBlockMap.put(id, state); - } catch (Exception e) { - log.warn("Unknown block: " + blockEntry.getValue()); + } catch (InputParseException e) { + boolean fixed = false; + if (fixer != null) { + String newEntry = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, blockEntry.getValue(), 1631); + try { + BlockState state = WorldEdit.getInstance().getBlockFactory().parseFromInput(newEntry, parserContext).toImmutableState(); + blockToStringMap.put(state, id); + stringToBlockMap.put(id, state); + fixed = true; + } catch (InputParseException ignored) { + } + } + if (!fixed) { + log.warn("Unknown block: " + blockEntry.getValue()); + } } } for (Map.Entry itemEntry : dataFile.items.entrySet()) { - try { - String id = itemEntry.getKey(); - ItemType type = ItemTypes.get(itemEntry.getValue()); - checkNotNull(type); + String id = itemEntry.getKey(); + String value = itemEntry.getValue(); + ItemType type = ItemTypes.get(value); + if (type == null && fixer != null) { + value = fixer.fixUp(DataFixer.FixTypes.ITEM_TYPE, value, 1631); + type = ItemTypes.get(value); + } + if (type == null) { + log.warn("Unknown item: " + value); + } else { itemToStringMap.put(type, id); stringToItemMap.put(id, type); - } catch (Exception e) { - log.warn("Unknown item: " + itemEntry.getValue()); } } } @@ -118,16 +140,16 @@ public class LegacyMapper { @Nullable public ItemType getItemFromLegacy(int legacyId, int data) { - return stringToItemMap.get(legacyId + ":" + data).stream().findFirst().orElse(null); + return stringToItemMap.get(legacyId + ":" + data); } @Nullable public int[] getLegacyFromItem(ItemType itemType) { - if (!itemToStringMap.containsKey(itemType)) { - return null; - } else { + if (itemToStringMap.containsKey(itemType)) { String value = itemToStringMap.get(itemType).stream().findFirst().get(); return Arrays.stream(value.split(":")).mapToInt(Integer::parseInt).toArray(); + } else { + return null; } } @@ -138,16 +160,16 @@ public class LegacyMapper { @Nullable public BlockState getBlockFromLegacy(int legacyId, int data) { - return stringToBlockMap.get(legacyId + ":" + data).stream().findFirst().orElse(null); + return stringToBlockMap.get(legacyId + ":" + data); } @Nullable public int[] getLegacyFromBlock(BlockState blockState) { - if (!blockToStringMap.containsKey(blockState)) { - return null; - } else { + if (blockToStringMap.containsKey(blockState)) { String value = blockToStringMap.get(blockState).stream().findFirst().get(); return Arrays.stream(value.split(":")).mapToInt(Integer::parseInt).toArray(); + } else { + return null; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java index fef791531..a965943cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/PassthroughBlockMaterial.java @@ -160,7 +160,7 @@ public class PassthroughBlockMaterial implements BlockMaterial { if (blockMaterial == null) { return true; } else { - return blockMaterial.isOpaque(); + return blockMaterial.isBurnable(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java index 1243a25fb..edd0799b4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java @@ -106,12 +106,13 @@ public abstract class ChunkStore implements Closeable { } int dataVersion = rootTag.getInt("DataVersion"); + if (dataVersion == 0) dataVersion = -1; final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); final int currentDataVersion = platform.getDataVersion(); if (dataVersion < currentDataVersion) { final DataFixer dataFixer = platform.getDataFixer(); if (dataFixer != null) { - return new AnvilChunk13((CompoundTag) dataFixer.fixChunk(rootTag).getValue().get("Level")); + return new AnvilChunk13((CompoundTag) dataFixer.fixUp(DataFixer.FixTypes.CHUNK, rootTag, dataVersion).getValue().get("Level")); } } if (dataVersion >= DATA_VERSION_MC_1_13) { From feed5173ec1841a7615cf5ef0843525b23324072 Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 17 May 2019 19:39:18 -0400 Subject: [PATCH 146/366] Add Forge DataFixer. Unsure how useful this will be, but eh. --- config/checkstyle/import-control.xml | 1 + .../sk89q/worldedit/forge/ForgeDataFixer.java | 2730 +++++++++++++++++ .../sk89q/worldedit/forge/ForgePlatform.java | 8 + 3 files changed, 2739 insertions(+) create mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 36ccf3d0b..c783552a9 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -57,6 +57,7 @@ + diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java new file mode 100644 index 000000000..30e5ae74f --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java @@ -0,0 +1,2730 @@ +/* + * 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.forge; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.datafixers.DSL.TypeReference; +import com.mojang.datafixers.DataFixTypes; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.DataFixerBuilder; +import com.mojang.datafixers.Dynamic; +import com.mojang.datafixers.schemas.Schema; +import com.sk89q.jnbt.CompoundTag; +import net.minecraft.item.EnumDyeColor; +import net.minecraft.nbt.INBTBase; +import net.minecraft.nbt.NBTDynamicOps; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagString; +import net.minecraft.nbt.NBTTagFloat; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.JsonUtils; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StringUtils; +import net.minecraft.util.datafix.DataFixesManager; +import net.minecraft.util.datafix.TypeReferences; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextComponentString; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.annotation.Nullable; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Executor; +import java.util.stream.Collectors; + +/** + * Handles converting all Pre 1.13.2 data using the Legacy DataFix System (ported to 1.13.2) + * + * We register a DFU Fixer per Legacy Data Version and apply the fixes using legacy strategy + * which is safer, faster and cleaner code. + * + * The pre DFU code did not fail when the Source version was unknown. + * + * This class also provides util methods for converting compounds to wrap the update call to + * receive the source version in the compound + * + */ +@SuppressWarnings("UnnecessarilyQualifiedStaticUsage") +class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { + + @SuppressWarnings("unchecked") + @Override + public T fixUp(FixType type, T original, int srcVer) { + if (type == FixTypes.CHUNK) { + return (T) fixChunk((CompoundTag) original, srcVer); + } else if (type == FixTypes.BLOCK_ENTITY) { + return (T) fixBlockEntity((CompoundTag) original, srcVer); + } else if (type == FixTypes.ENTITY) { + return (T) fixEntity((CompoundTag) original, srcVer); + } else if (type == FixTypes.BLOCK_STATE) { + return (T) fixBlockState((String) original, srcVer); + } else if (type == FixTypes.ITEM_TYPE) { + return (T) fixItemType((String) original, srcVer); + } else if (type == FixTypes.BIOME) { + return (T) fixBiome((String) original, srcVer); + } + return original; + } + + private CompoundTag fixChunk(CompoundTag originalChunk, int srcVer) { + NBTTagCompound tag = NBTConverter.toNative(originalChunk); + NBTTagCompound fixed = convert(LegacyType.CHUNK, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private CompoundTag fixBlockEntity(CompoundTag origTileEnt, int srcVer) { + NBTTagCompound tag = NBTConverter.toNative(origTileEnt); + NBTTagCompound fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private CompoundTag fixEntity(CompoundTag origEnt, int srcVer) { + NBTTagCompound tag = NBTConverter.toNative(origEnt); + NBTTagCompound fixed = convert(LegacyType.ENTITY, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private String fixBlockState(String blockState, int srcVer) { + NBTTagCompound stateNBT = stateToNBT(blockState); + Dynamic dynamic = new Dynamic<>(OPS_NBT, stateNBT); + NBTTagCompound fixed = (NBTTagCompound) INSTANCE.fixer.update(TypeReferences.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); + return nbtToState(fixed); + } + + private String nbtToState(NBTTagCompound tagCompound) { + StringBuilder sb = new StringBuilder(); + sb.append(tagCompound.getString("Name")); + if (tagCompound.contains("Properties", 10)) { + sb.append('['); + NBTTagCompound props = tagCompound.getCompound("Properties"); + sb.append(props.keySet().stream().map(k -> k + "=" + props.getString(k).replace("\"", "")).collect(Collectors.joining(","))); + sb.append(']'); + } + return sb.toString(); + } + + private static NBTTagCompound stateToNBT(String blockState) { + int propIdx = blockState.indexOf('['); + NBTTagCompound tag = new NBTTagCompound(); + if (propIdx < 0) { + tag.putString("Name", blockState); + } else { + tag.putString("Name", blockState.substring(0, propIdx)); + NBTTagCompound propTag = new NBTTagCompound(); + String props = blockState.substring(propIdx + 1, blockState.length() - 1); + String[] propArr = props.split(","); + for (String pair : propArr) { + final String[] split = pair.split("="); + propTag.putString(split[0], split[1]); + } + tag.put("Properties", propTag); + } + return tag; + } + + private String fixBiome(String key, int srcVer) { + return fixName(key, srcVer, TypeReferences.BIOME); + } + + private String fixItemType(String key, int srcVer) { + return fixName(key, srcVer, TypeReferences.ITEM_NAME); + } + + private static String fixName(String key, int srcVer, TypeReference type) { + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, new NBTTagString(key)), srcVer, DATA_VERSION) + .getStringValue().orElse(key); + } + + private static final NBTDynamicOps OPS_NBT = NBTDynamicOps.INSTANCE; + private static final int LEGACY_VERSION = 1343; + private static int DATA_VERSION; + private static ForgeDataFixer INSTANCE; + + private final Map> converters = new EnumMap<>(LegacyType.class); + private final Map> inspectors = new EnumMap<>(LegacyType.class); + + // Set on build + private DataFixer fixer; + private static final Map DFU_TO_LEGACY = new HashMap<>(); + + public enum LegacyType { + LEVEL(DataFixTypes.LEVEL), + PLAYER(DataFixTypes.PLAYER), + CHUNK(DataFixTypes.CHUNK), + BLOCK_ENTITY(TypeReferences.BLOCK_ENTITY), + ENTITY(TypeReferences.ENTITY), + ITEM_INSTANCE(TypeReferences.ITEM_STACK), + OPTIONS(DataFixTypes.OPTIONS), + STRUCTURE(DataFixTypes.STRUCTURE); + + private final TypeReference type; + + LegacyType(TypeReference type) { + this.type = type; + DFU_TO_LEGACY.put(type.typeName(), this); + } + + public TypeReference getDFUType() { + return type; + } + } + + public ForgeDataFixer(int dataVersion) { + super(dataVersion); + DATA_VERSION = dataVersion; + INSTANCE = this; + registerConverters(); + registerInspectors(); + } + + + // Called after fixers are built and ready for FIXING + @Override + public DataFixer build(final Executor executor) { + return this.fixer = new WrappedDataFixer(DataFixesManager.getDataFixer()); + } + + private class WrappedDataFixer implements DataFixer { + private final DataFixer realFixer; + + WrappedDataFixer(DataFixer realFixer) { + this.realFixer = realFixer; + } + + @Override + public Dynamic update(TypeReference type, Dynamic dynamic, int sourceVer, int targetVer) { + LegacyType legacyType = DFU_TO_LEGACY.get(type.typeName()); + if (sourceVer < LEGACY_VERSION && legacyType != null) { + NBTTagCompound cmp = (NBTTagCompound) dynamic.getValue(); + int desiredVersion = Math.min(targetVer, LEGACY_VERSION); + + cmp = convert(legacyType, cmp, sourceVer, desiredVersion); + sourceVer = desiredVersion; + dynamic = new Dynamic(OPS_NBT, cmp); + } + return realFixer.update(type, dynamic, sourceVer, targetVer); + } + + private NBTTagCompound convert(LegacyType type, NBTTagCompound cmp, int sourceVer, int desiredVersion) { + List converters = ForgeDataFixer.this.converters.get(type); + if (converters != null && !converters.isEmpty()) { + for (DataConverter converter : converters) { + int dataVersion = converter.getDataVersion(); + if (dataVersion > sourceVer && dataVersion <= desiredVersion) { + cmp = converter.convert(cmp); + } + } + } + + List inspectors = ForgeDataFixer.this.inspectors.get(type); + if (inspectors != null && !inspectors.isEmpty()) { + for (DataInspector inspector : inspectors) { + cmp = inspector.inspect(cmp, sourceVer, desiredVersion); + } + } + + return cmp; + } + + @Override + public Schema getSchema(int i) { + return realFixer.getSchema(i); + } + } + + public static NBTTagCompound convert(LegacyType type, NBTTagCompound cmp) { + return convert(type.getDFUType(), cmp); + } + + public static NBTTagCompound convert(LegacyType type, NBTTagCompound cmp, int sourceVer) { + return convert(type.getDFUType(), cmp, sourceVer); + } + + public static NBTTagCompound convert(LegacyType type, NBTTagCompound cmp, int sourceVer, int targetVer) { + return convert(type.getDFUType(), cmp, sourceVer, targetVer); + } + + public static NBTTagCompound convert(TypeReference type, NBTTagCompound cmp) { + int i = cmp.contains("DataVersion", 99) ? cmp.getInt("DataVersion") : -1; + return convert(type, cmp, i); + } + + public static NBTTagCompound convert(TypeReference type, NBTTagCompound cmp, int sourceVer) { + return convert(type, cmp, sourceVer, DATA_VERSION); + } + + public static NBTTagCompound convert(TypeReference type, NBTTagCompound cmp, int sourceVer, int targetVer) { + if (sourceVer >= targetVer) { + return cmp; + } + return (NBTTagCompound) INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer).getValue(); + } + + + public interface DataInspector { + NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer); + } + + public interface DataConverter { + + int getDataVersion(); + + NBTTagCompound convert(NBTTagCompound cmp); + } + + + private void registerInspector(LegacyType type, DataInspector inspector) { + this.inspectors.computeIfAbsent(type, k -> new ArrayList<>()).add(inspector); + } + + private void registerConverter(LegacyType type, DataConverter converter) { + int version = converter.getDataVersion(); + + List list = this.converters.computeIfAbsent(type, k -> new ArrayList<>()); + if (!list.isEmpty() && list.get(list.size() - 1).getDataVersion() > version) { + for (int j = 0; j < list.size(); ++j) { + if (list.get(j).getDataVersion() > version) { + list.add(j, converter); + break; + } + } + } else { + list.add(converter); + } + } + + private void registerInspectors() { + registerEntityItemList("EntityHorseDonkey", "SaddleItem", "Items"); + registerEntityItemList("EntityHorseMule", "Items"); + registerEntityItemList("EntityMinecartChest", "Items"); + registerEntityItemList("EntityMinecartHopper", "Items"); + registerEntityItemList("EntityVillager", "Inventory"); + registerEntityItemListEquipment("EntityArmorStand"); + registerEntityItemListEquipment("EntityBat"); + registerEntityItemListEquipment("EntityBlaze"); + registerEntityItemListEquipment("EntityCaveSpider"); + registerEntityItemListEquipment("EntityChicken"); + registerEntityItemListEquipment("EntityCow"); + registerEntityItemListEquipment("EntityCreeper"); + registerEntityItemListEquipment("EntityEnderDragon"); + registerEntityItemListEquipment("EntityEnderman"); + registerEntityItemListEquipment("EntityEndermite"); + registerEntityItemListEquipment("EntityEvoker"); + registerEntityItemListEquipment("EntityGhast"); + registerEntityItemListEquipment("EntityGiantZombie"); + registerEntityItemListEquipment("EntityGuardian"); + registerEntityItemListEquipment("EntityGuardianElder"); + registerEntityItemListEquipment("EntityHorse"); + registerEntityItemListEquipment("EntityHorseDonkey"); + registerEntityItemListEquipment("EntityHorseMule"); + registerEntityItemListEquipment("EntityHorseSkeleton"); + registerEntityItemListEquipment("EntityHorseZombie"); + registerEntityItemListEquipment("EntityIronGolem"); + registerEntityItemListEquipment("EntityMagmaCube"); + registerEntityItemListEquipment("EntityMushroomCow"); + registerEntityItemListEquipment("EntityOcelot"); + registerEntityItemListEquipment("EntityPig"); + registerEntityItemListEquipment("EntityPigZombie"); + registerEntityItemListEquipment("EntityRabbit"); + registerEntityItemListEquipment("EntitySheep"); + registerEntityItemListEquipment("EntityShulker"); + registerEntityItemListEquipment("EntitySilverfish"); + registerEntityItemListEquipment("EntitySkeleton"); + registerEntityItemListEquipment("EntitySkeletonStray"); + registerEntityItemListEquipment("EntitySkeletonWither"); + registerEntityItemListEquipment("EntitySlime"); + registerEntityItemListEquipment("EntitySnowman"); + registerEntityItemListEquipment("EntitySpider"); + registerEntityItemListEquipment("EntitySquid"); + registerEntityItemListEquipment("EntityVex"); + registerEntityItemListEquipment("EntityVillager"); + registerEntityItemListEquipment("EntityVindicator"); + registerEntityItemListEquipment("EntityWitch"); + registerEntityItemListEquipment("EntityWither"); + registerEntityItemListEquipment("EntityWolf"); + registerEntityItemListEquipment("EntityZombie"); + registerEntityItemListEquipment("EntityZombieHusk"); + registerEntityItemListEquipment("EntityZombieVillager"); + registerEntityItemSingle("EntityFireworks", "FireworksItem"); + registerEntityItemSingle("EntityHorse", "ArmorItem"); + registerEntityItemSingle("EntityHorse", "SaddleItem"); + registerEntityItemSingle("EntityHorseMule", "SaddleItem"); + registerEntityItemSingle("EntityHorseSkeleton", "SaddleItem"); + registerEntityItemSingle("EntityHorseZombie", "SaddleItem"); + registerEntityItemSingle("EntityItem", "Item"); + registerEntityItemSingle("EntityItemFrame", "Item"); + registerEntityItemSingle("EntityPotion", "Potion"); + + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItem("TileEntityRecordPlayer", "RecordItem")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityBrewingStand", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityChest", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityDispenser", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityDropper", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityFurnace", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityHopper", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityShulkerBox", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorMobSpawnerMobs()); + registerInspector(LegacyType.CHUNK, new DataInspectorChunks()); + registerInspector(LegacyType.ENTITY, new DataInspectorCommandBlock()); + registerInspector(LegacyType.ENTITY, new DataInspectorEntityPassengers()); + registerInspector(LegacyType.ENTITY, new DataInspectorMobSpawnerMinecart()); + registerInspector(LegacyType.ENTITY, new DataInspectorVillagers()); + registerInspector(LegacyType.ITEM_INSTANCE, new DataInspectorBlockEntity()); + registerInspector(LegacyType.ITEM_INSTANCE, new DataInspectorEntity()); + registerInspector(LegacyType.LEVEL, new DataInspectorLevelPlayer()); + registerInspector(LegacyType.PLAYER, new DataInspectorPlayer()); + registerInspector(LegacyType.PLAYER, new DataInspectorPlayerVehicle()); + registerInspector(LegacyType.STRUCTURE, new DataInspectorStructure()); + } + + private void registerConverters() { + registerConverter(LegacyType.ENTITY, new DataConverterEquipment()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterSignText()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterMaterialId()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterPotionId()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterSpawnEgg()); + registerConverter(LegacyType.ENTITY, new DataConverterMinecart()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterMobSpawner()); + registerConverter(LegacyType.ENTITY, new DataConverterUUID()); + registerConverter(LegacyType.ENTITY, new DataConverterHealth()); + registerConverter(LegacyType.ENTITY, new DataConverterSaddle()); + registerConverter(LegacyType.ENTITY, new DataConverterHanging()); + registerConverter(LegacyType.ENTITY, new DataConverterDropChances()); + registerConverter(LegacyType.ENTITY, new DataConverterRiding()); + registerConverter(LegacyType.ENTITY, new DataConverterArmorStand()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBook()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterCookedFish()); + registerConverter(LegacyType.ENTITY, new DataConverterZombie()); + registerConverter(LegacyType.OPTIONS, new DataConverterVBO()); + registerConverter(LegacyType.ENTITY, new DataConverterGuardian()); + registerConverter(LegacyType.ENTITY, new DataConverterSkeleton()); + registerConverter(LegacyType.ENTITY, new DataConverterZombieType()); + registerConverter(LegacyType.ENTITY, new DataConverterHorse()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterTileEntity()); + registerConverter(LegacyType.ENTITY, new DataConverterEntity()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBanner()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterPotionWater()); + registerConverter(LegacyType.ENTITY, new DataConverterShulker()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterShulkerBoxItem()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterShulkerBoxBlock()); + registerConverter(LegacyType.OPTIONS, new DataConverterLang()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterTotem()); + registerConverter(LegacyType.CHUNK, new DataConverterBedBlock()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBedItem()); + } + + private void registerEntityItemList(String type, String... keys) { + registerInspector(LegacyType.ENTITY, new DataInspectorItemList(type, keys)); + } + + private void registerEntityItemSingle(String type, String key) { + registerInspector(LegacyType.ENTITY, new DataInspectorItem(type, key)); + } + + private void registerEntityItemListEquipment(String type) { + registerEntityItemList(type, "ArmorItems", "HandItems"); + } + private static final Map OLD_ID_TO_KEY_MAP = new HashMap<>(); + + static { + final Map map = OLD_ID_TO_KEY_MAP; + map.put("EntityItem", new ResourceLocation("item")); + map.put("EntityExperienceOrb", new ResourceLocation("xp_orb")); + map.put("EntityAreaEffectCloud", new ResourceLocation("area_effect_cloud")); + map.put("EntityGuardianElder", new ResourceLocation("elder_guardian")); + map.put("EntitySkeletonWither", new ResourceLocation("wither_skeleton")); + map.put("EntitySkeletonStray", new ResourceLocation("stray")); + map.put("EntityEgg", new ResourceLocation("egg")); + map.put("EntityLeash", new ResourceLocation("leash_knot")); + map.put("EntityPainting", new ResourceLocation("painting")); + map.put("EntityTippedArrow", new ResourceLocation("arrow")); + map.put("EntitySnowball", new ResourceLocation("snowball")); + map.put("EntityLargeFireball", new ResourceLocation("fireball")); + map.put("EntitySmallFireball", new ResourceLocation("small_fireball")); + map.put("EntityEnderPearl", new ResourceLocation("ender_pearl")); + map.put("EntityEnderSignal", new ResourceLocation("eye_of_ender_signal")); + map.put("EntityPotion", new ResourceLocation("potion")); + map.put("EntityThrownExpBottle", new ResourceLocation("xp_bottle")); + map.put("EntityItemFrame", new ResourceLocation("item_frame")); + map.put("EntityWitherSkull", new ResourceLocation("wither_skull")); + map.put("EntityTNTPrimed", new ResourceLocation("tnt")); + map.put("EntityFallingBlock", new ResourceLocation("falling_block")); + map.put("EntityFireworks", new ResourceLocation("fireworks_rocket")); + map.put("EntityZombieHusk", new ResourceLocation("husk")); + map.put("EntitySpectralArrow", new ResourceLocation("spectral_arrow")); + map.put("EntityShulkerBullet", new ResourceLocation("shulker_bullet")); + map.put("EntityDragonFireball", new ResourceLocation("dragon_fireball")); + map.put("EntityZombieVillager", new ResourceLocation("zombie_villager")); + map.put("EntityHorseSkeleton", new ResourceLocation("skeleton_horse")); + map.put("EntityHorseZombie", new ResourceLocation("zombie_horse")); + map.put("EntityArmorStand", new ResourceLocation("armor_stand")); + map.put("EntityHorseDonkey", new ResourceLocation("donkey")); + map.put("EntityHorseMule", new ResourceLocation("mule")); + map.put("EntityEvokerFangs", new ResourceLocation("evocation_fangs")); + map.put("EntityEvoker", new ResourceLocation("evocation_illager")); + map.put("EntityVex", new ResourceLocation("vex")); + map.put("EntityVindicator", new ResourceLocation("vindication_illager")); + map.put("EntityIllagerIllusioner", new ResourceLocation("illusion_illager")); + map.put("EntityMinecartCommandBlock", new ResourceLocation("commandblock_minecart")); + map.put("EntityBoat", new ResourceLocation("boat")); + map.put("EntityMinecartRideable", new ResourceLocation("minecart")); + map.put("EntityMinecartChest", new ResourceLocation("chest_minecart")); + map.put("EntityMinecartFurnace", new ResourceLocation("furnace_minecart")); + map.put("EntityMinecartTNT", new ResourceLocation("tnt_minecart")); + map.put("EntityMinecartHopper", new ResourceLocation("hopper_minecart")); + map.put("EntityMinecartMobSpawner", new ResourceLocation("spawner_minecart")); + map.put("EntityCreeper", new ResourceLocation("creeper")); + map.put("EntitySkeleton", new ResourceLocation("skeleton")); + map.put("EntitySpider", new ResourceLocation("spider")); + map.put("EntityGiantZombie", new ResourceLocation("giant")); + map.put("EntityZombie", new ResourceLocation("zombie")); + map.put("EntitySlime", new ResourceLocation("slime")); + map.put("EntityGhast", new ResourceLocation("ghast")); + map.put("EntityPigZombie", new ResourceLocation("zombie_pigman")); + map.put("EntityEnderman", new ResourceLocation("enderman")); + map.put("EntityCaveSpider", new ResourceLocation("cave_spider")); + map.put("EntitySilverfish", new ResourceLocation("silverfish")); + map.put("EntityBlaze", new ResourceLocation("blaze")); + map.put("EntityMagmaCube", new ResourceLocation("magma_cube")); + map.put("EntityEnderDragon", new ResourceLocation("ender_dragon")); + map.put("EntityWither", new ResourceLocation("wither")); + map.put("EntityBat", new ResourceLocation("bat")); + map.put("EntityWitch", new ResourceLocation("witch")); + map.put("EntityEndermite", new ResourceLocation("endermite")); + map.put("EntityGuardian", new ResourceLocation("guardian")); + map.put("EntityShulker", new ResourceLocation("shulker")); + map.put("EntityPig", new ResourceLocation("pig")); + map.put("EntitySheep", new ResourceLocation("sheep")); + map.put("EntityCow", new ResourceLocation("cow")); + map.put("EntityChicken", new ResourceLocation("chicken")); + map.put("EntitySquid", new ResourceLocation("squid")); + map.put("EntityWolf", new ResourceLocation("wolf")); + map.put("EntityMushroomCow", new ResourceLocation("mooshroom")); + map.put("EntitySnowman", new ResourceLocation("snowman")); + map.put("EntityOcelot", new ResourceLocation("ocelot")); + map.put("EntityIronGolem", new ResourceLocation("villager_golem")); + map.put("EntityHorse", new ResourceLocation("horse")); + map.put("EntityRabbit", new ResourceLocation("rabbit")); + map.put("EntityPolarBear", new ResourceLocation("polar_bear")); + map.put("EntityLlama", new ResourceLocation("llama")); + map.put("EntityLlamaSpit", new ResourceLocation("llama_spit")); + map.put("EntityParrot", new ResourceLocation("parrot")); + map.put("EntityVillager", new ResourceLocation("villager")); + map.put("EntityEnderCrystal", new ResourceLocation("ender_crystal")); + map.put("TileEntityFurnace", new ResourceLocation("furnace")); + map.put("TileEntityChest", new ResourceLocation("chest")); + map.put("TileEntityEnderChest", new ResourceLocation("ender_chest")); + map.put("TileEntityRecordPlayer", new ResourceLocation("jukebox")); + map.put("TileEntityDispenser", new ResourceLocation("dispenser")); + map.put("TileEntityDropper", new ResourceLocation("dropper")); + map.put("TileEntitySign", new ResourceLocation("sign")); + map.put("TileEntityMobSpawner", new ResourceLocation("mob_spawner")); + map.put("TileEntityNote", new ResourceLocation("noteblock")); + map.put("TileEntityPiston", new ResourceLocation("piston")); + map.put("TileEntityBrewingStand", new ResourceLocation("brewing_stand")); + map.put("TileEntityEnchantTable", new ResourceLocation("enchanting_table")); + map.put("TileEntityEnderPortal", new ResourceLocation("end_portal")); + map.put("TileEntityBeacon", new ResourceLocation("beacon")); + map.put("TileEntitySkull", new ResourceLocation("skull")); + map.put("TileEntityLightDetector", new ResourceLocation("daylight_detector")); + map.put("TileEntityHopper", new ResourceLocation("hopper")); + map.put("TileEntityComparator", new ResourceLocation("comparator")); + map.put("TileEntityFlowerPot", new ResourceLocation("flower_pot")); + map.put("TileEntityBanner", new ResourceLocation("banner")); + map.put("TileEntityStructure", new ResourceLocation("structure_block")); + map.put("TileEntityEndGateway", new ResourceLocation("end_gateway")); + map.put("TileEntityCommand", new ResourceLocation("command_block")); + map.put("TileEntityShulkerBox", new ResourceLocation("shulker_box")); + map.put("TileEntityBed", new ResourceLocation("bed")); + } + + private static ResourceLocation getKey(String type) { + final ResourceLocation key = OLD_ID_TO_KEY_MAP.get(type); + if (key == null) { + throw new IllegalArgumentException("Unknown mapping for " + type); + } + return key; + } + + private static void convertCompound(LegacyType type, NBTTagCompound cmp, String key, int sourceVer, int targetVer) { + cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, targetVer)); + } + + private static void convertItem(NBTTagCompound nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 10)) { + convertCompound(LegacyType.ITEM_INSTANCE, nbttagcompound, key, sourceVer, targetVer); + } + } + + private static void convertItems(NBTTagCompound nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.contains(key, 9)) { + NBTTagList nbttaglist = nbttagcompound.getList(key, 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.add(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } + + } + + private static class DataConverterEquipment implements DataConverter { + + DataConverterEquipment() {} + + @Override + public int getDataVersion() { + return 100; + } + + @Override + public NBTTagCompound convert(NBTTagCompound cmp) { + NBTTagList nbttaglist = cmp.getList("Equipment", 10); + NBTTagList nbttaglist1; + + if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { + nbttaglist1 = new NBTTagList(); + nbttaglist1.add(nbttaglist.get(0)); + nbttaglist1.add(new NBTTagCompound()); + cmp.put("HandItems", nbttaglist1); + } + + if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { + nbttaglist1 = new NBTTagList(); + nbttaglist1.add(nbttaglist.get(1)); + nbttaglist1.add(nbttaglist.get(2)); + nbttaglist1.add(nbttaglist.get(3)); + nbttaglist1.add(nbttaglist.get(4)); + cmp.put("ArmorItems", nbttaglist1); + } + + cmp.remove("Equipment"); + if (cmp.contains("DropChances", 9)) { + nbttaglist1 = cmp.getList("DropChances", 5); + NBTTagList nbttaglist2; + + if (!cmp.contains("HandDropChances", 10)) { + nbttaglist2 = new NBTTagList(); + nbttaglist2.add(new NBTTagFloat(nbttaglist1.getFloat(0))); + nbttaglist2.add(new NBTTagFloat(0.0F)); + cmp.put("HandDropChances", nbttaglist2); + } + + if (!cmp.contains("ArmorDropChances", 10)) { + nbttaglist2 = new NBTTagList(); + nbttaglist2.add(new NBTTagFloat(nbttaglist1.getFloat(1))); + nbttaglist2.add(new NBTTagFloat(nbttaglist1.getFloat(2))); + nbttaglist2.add(new NBTTagFloat(nbttaglist1.getFloat(3))); + nbttaglist2.add(new NBTTagFloat(nbttaglist1.getFloat(4))); + cmp.put("ArmorDropChances", nbttaglist2); + } + + cmp.remove("DropChances"); + } + + return cmp; + } + } + + private static class DataInspectorBlockEntity implements DataInspector { + + private static final Map b = Maps.newHashMap(); + private static final Map c = Maps.newHashMap(); + + DataInspectorBlockEntity() {} + + @Nullable + private static String convertEntityId(int i, String s) { + String key = new ResourceLocation(s).toString(); + if (i < 515 && DataInspectorBlockEntity.b.containsKey(key)) { + return DataInspectorBlockEntity.b.get(key); + } else { + return DataInspectorBlockEntity.c.get(key); + } + } + + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + if (!cmp.contains("tag", 10)) { + return cmp; + } else { + NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + NBTTagCompound nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + String s = cmp.getString("id"); + String s1 = convertEntityId(sourceVer, s); + boolean flag; + + if (s1 == null) { + // CraftBukkit - Remove unnecessary warning (occurs when deserializing a Shulker Box item) + // DataInspectorBlockEntity.a.warn("Unable to resolve BlockEntity for ItemInstance: {}", s); + flag = false; + } else { + flag = !nbttagcompound2.contains("id"); + nbttagcompound2.putString("id", s1); + } + + convert(LegacyType.BLOCK_ENTITY, nbttagcompound2, sourceVer, targetVer); + if (flag) { + nbttagcompound2.remove("id"); + } + } + + return cmp; + } + } + + static { + Map map = DataInspectorBlockEntity.b; + + map.put("minecraft:furnace", "Furnace"); + map.put("minecraft:lit_furnace", "Furnace"); + map.put("minecraft:chest", "Chest"); + map.put("minecraft:trapped_chest", "Chest"); + map.put("minecraft:ender_chest", "EnderChest"); + map.put("minecraft:jukebox", "RecordPlayer"); + map.put("minecraft:dispenser", "Trap"); + map.put("minecraft:dropper", "Dropper"); + map.put("minecraft:sign", "Sign"); + map.put("minecraft:mob_spawner", "MobSpawner"); + map.put("minecraft:noteblock", "Music"); + map.put("minecraft:brewing_stand", "Cauldron"); + map.put("minecraft:enhanting_table", "EnchantTable"); + map.put("minecraft:command_block", "CommandBlock"); + map.put("minecraft:beacon", "Beacon"); + map.put("minecraft:skull", "Skull"); + map.put("minecraft:daylight_detector", "DLDetector"); + map.put("minecraft:hopper", "Hopper"); + map.put("minecraft:banner", "Banner"); + map.put("minecraft:flower_pot", "FlowerPot"); + map.put("minecraft:repeating_command_block", "CommandBlock"); + map.put("minecraft:chain_command_block", "CommandBlock"); + map.put("minecraft:standing_sign", "Sign"); + map.put("minecraft:wall_sign", "Sign"); + map.put("minecraft:piston_head", "Piston"); + map.put("minecraft:daylight_detector_inverted", "DLDetector"); + map.put("minecraft:unpowered_comparator", "Comparator"); + map.put("minecraft:powered_comparator", "Comparator"); + map.put("minecraft:wall_banner", "Banner"); + map.put("minecraft:standing_banner", "Banner"); + map.put("minecraft:structure_block", "Structure"); + map.put("minecraft:end_portal", "Airportal"); + map.put("minecraft:end_gateway", "EndGateway"); + map.put("minecraft:shield", "Shield"); + map = DataInspectorBlockEntity.c; + map.put("minecraft:furnace", "minecraft:furnace"); + map.put("minecraft:lit_furnace", "minecraft:furnace"); + map.put("minecraft:chest", "minecraft:chest"); + map.put("minecraft:trapped_chest", "minecraft:chest"); + map.put("minecraft:ender_chest", "minecraft:enderchest"); + map.put("minecraft:jukebox", "minecraft:jukebox"); + map.put("minecraft:dispenser", "minecraft:dispenser"); + map.put("minecraft:dropper", "minecraft:dropper"); + map.put("minecraft:sign", "minecraft:sign"); + map.put("minecraft:mob_spawner", "minecraft:mob_spawner"); + map.put("minecraft:noteblock", "minecraft:noteblock"); + map.put("minecraft:brewing_stand", "minecraft:brewing_stand"); + map.put("minecraft:enhanting_table", "minecraft:enchanting_table"); + map.put("minecraft:command_block", "minecraft:command_block"); + map.put("minecraft:beacon", "minecraft:beacon"); + map.put("minecraft:skull", "minecraft:skull"); + map.put("minecraft:daylight_detector", "minecraft:daylight_detector"); + map.put("minecraft:hopper", "minecraft:hopper"); + map.put("minecraft:banner", "minecraft:banner"); + map.put("minecraft:flower_pot", "minecraft:flower_pot"); + map.put("minecraft:repeating_command_block", "minecraft:command_block"); + map.put("minecraft:chain_command_block", "minecraft:command_block"); + map.put("minecraft:shulker_box", "minecraft:shulker_box"); + map.put("minecraft:white_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:orange_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:magenta_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:light_blue_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:yellow_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:lime_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:pink_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:gray_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:silver_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:cyan_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:purple_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:blue_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:brown_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:green_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:red_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:black_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:bed", "minecraft:bed"); + map.put("minecraft:standing_sign", "minecraft:sign"); + map.put("minecraft:wall_sign", "minecraft:sign"); + map.put("minecraft:piston_head", "minecraft:piston"); + map.put("minecraft:daylight_detector_inverted", "minecraft:daylight_detector"); + map.put("minecraft:unpowered_comparator", "minecraft:comparator"); + map.put("minecraft:powered_comparator", "minecraft:comparator"); + map.put("minecraft:wall_banner", "minecraft:banner"); + map.put("minecraft:standing_banner", "minecraft:banner"); + map.put("minecraft:structure_block", "minecraft:structure_block"); + map.put("minecraft:end_portal", "minecraft:end_portal"); + map.put("minecraft:end_gateway", "minecraft:end_gateway"); + map.put("minecraft:shield", "minecraft:shield"); + } + } + + private static class DataInspectorEntity implements DataInspector { + + private static final Logger a = LogManager.getLogger(ForgeDataFixer.class); + + DataInspectorEntity() {} + + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("EntityTag", 10)) { + NBTTagCompound nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + String s = cmp.getString("id"); + String s1; + + if ("minecraft:armor_stand".equals(s)) { + s1 = sourceVer < 515 ? "ArmorStand" : "minecraft:armor_stand"; + } else { + if (!"minecraft:spawn_egg".equals(s)) { + return cmp; + } + + s1 = nbttagcompound2.getString("id"); + } + + boolean flag; + + if (s1 == null) { + DataInspectorEntity.a.warn("Unable to resolve Entity for ItemInstance: {}", s); + flag = false; + } else { + flag = !nbttagcompound2.contains("id", 8); + nbttagcompound2.putString("id", s1); + } + + convert(LegacyType.ENTITY, nbttagcompound2, sourceVer, targetVer); + if (flag) { + nbttagcompound2.remove("id"); + } + } + + return cmp; + } + } + + + private abstract static class DataInspectorTagged implements DataInspector { + + private final ResourceLocation key; + + DataInspectorTagged(String type) { + this.key = getKey(type); + } + + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + if (this.key.equals(new ResourceLocation(cmp.getString("id")))) { + cmp = this.inspectChecked(cmp, sourceVer, targetVer); + } + + return cmp; + } + + abstract NBTTagCompound inspectChecked(NBTTagCompound nbttagcompound, int sourceVer, int targetVer); + } + + private static class DataInspectorItemList extends DataInspectorTagged { + + private final String[] keys; + + DataInspectorItemList(String oclass, String... astring) { + super(oclass); + this.keys = astring; + } + + NBTTagCompound inspectChecked(NBTTagCompound nbttagcompound, int sourceVer, int targetVer) { + for (String s : this.keys) { + ForgeDataFixer.convertItems(nbttagcompound, s, sourceVer, targetVer); + } + + return nbttagcompound; + } + } + private static class DataInspectorItem extends DataInspectorTagged { + + private final String[] keys; + + DataInspectorItem(String oclass, String... astring) { + super(oclass); + this.keys = astring; + } + + NBTTagCompound inspectChecked(NBTTagCompound nbttagcompound, int sourceVer, int targetVer) { + for (String key : this.keys) { + ForgeDataFixer.convertItem(nbttagcompound, key, sourceVer, targetVer); + } + + return nbttagcompound; + } + } + + private static class DataConverterMaterialId implements DataConverter { + + private static final String[] materials = new String[2268]; + + DataConverterMaterialId() {} + + public int getDataVersion() { + return 102; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if (cmp.contains("id", 99)) { + short short0 = cmp.getShort("id"); + + if (short0 > 0 && short0 < materials.length && materials[short0] != null) { + cmp.putString("id", materials[short0]); + } + } + + return cmp; + } + + static { + materials[1] = "minecraft:stone"; + materials[2] = "minecraft:grass"; + materials[3] = "minecraft:dirt"; + materials[4] = "minecraft:cobblestone"; + materials[5] = "minecraft:planks"; + materials[6] = "minecraft:sapling"; + materials[7] = "minecraft:bedrock"; + materials[8] = "minecraft:flowing_water"; + materials[9] = "minecraft:water"; + materials[10] = "minecraft:flowing_lava"; + materials[11] = "minecraft:lava"; + materials[12] = "minecraft:sand"; + materials[13] = "minecraft:gravel"; + materials[14] = "minecraft:gold_ore"; + materials[15] = "minecraft:iron_ore"; + materials[16] = "minecraft:coal_ore"; + materials[17] = "minecraft:log"; + materials[18] = "minecraft:leaves"; + materials[19] = "minecraft:sponge"; + materials[20] = "minecraft:glass"; + materials[21] = "minecraft:lapis_ore"; + materials[22] = "minecraft:lapis_block"; + materials[23] = "minecraft:dispenser"; + materials[24] = "minecraft:sandstone"; + materials[25] = "minecraft:noteblock"; + materials[27] = "minecraft:golden_rail"; + materials[28] = "minecraft:detector_rail"; + materials[29] = "minecraft:sticky_piston"; + materials[30] = "minecraft:web"; + materials[31] = "minecraft:tallgrass"; + materials[32] = "minecraft:deadbush"; + materials[33] = "minecraft:piston"; + materials[35] = "minecraft:wool"; + materials[37] = "minecraft:yellow_flower"; + materials[38] = "minecraft:red_flower"; + materials[39] = "minecraft:brown_mushroom"; + materials[40] = "minecraft:red_mushroom"; + materials[41] = "minecraft:gold_block"; + materials[42] = "minecraft:iron_block"; + materials[43] = "minecraft:double_stone_slab"; + materials[44] = "minecraft:stone_slab"; + materials[45] = "minecraft:brick_block"; + materials[46] = "minecraft:tnt"; + materials[47] = "minecraft:bookshelf"; + materials[48] = "minecraft:mossy_cobblestone"; + materials[49] = "minecraft:obsidian"; + materials[50] = "minecraft:torch"; + materials[51] = "minecraft:fire"; + materials[52] = "minecraft:mob_spawner"; + materials[53] = "minecraft:oak_stairs"; + materials[54] = "minecraft:chest"; + materials[56] = "minecraft:diamond_ore"; + materials[57] = "minecraft:diamond_block"; + materials[58] = "minecraft:crafting_table"; + materials[60] = "minecraft:farmland"; + materials[61] = "minecraft:furnace"; + materials[62] = "minecraft:lit_furnace"; + materials[65] = "minecraft:ladder"; + materials[66] = "minecraft:rail"; + materials[67] = "minecraft:stone_stairs"; + materials[69] = "minecraft:lever"; + materials[70] = "minecraft:stone_pressure_plate"; + materials[72] = "minecraft:wooden_pressure_plate"; + materials[73] = "minecraft:redstone_ore"; + materials[76] = "minecraft:redstone_torch"; + materials[77] = "minecraft:stone_button"; + materials[78] = "minecraft:snow_layer"; + materials[79] = "minecraft:ice"; + materials[80] = "minecraft:snow"; + materials[81] = "minecraft:cactus"; + materials[82] = "minecraft:clay"; + materials[84] = "minecraft:jukebox"; + materials[85] = "minecraft:fence"; + materials[86] = "minecraft:pumpkin"; + materials[87] = "minecraft:netherrack"; + materials[88] = "minecraft:soul_sand"; + materials[89] = "minecraft:glowstone"; + materials[90] = "minecraft:portal"; + materials[91] = "minecraft:lit_pumpkin"; + materials[95] = "minecraft:stained_glass"; + materials[96] = "minecraft:trapdoor"; + materials[97] = "minecraft:monster_egg"; + materials[98] = "minecraft:stonebrick"; + materials[99] = "minecraft:brown_mushroom_block"; + materials[100] = "minecraft:red_mushroom_block"; + materials[101] = "minecraft:iron_bars"; + materials[102] = "minecraft:glass_pane"; + materials[103] = "minecraft:melon_block"; + materials[106] = "minecraft:vine"; + materials[107] = "minecraft:fence_gate"; + materials[108] = "minecraft:brick_stairs"; + materials[109] = "minecraft:stone_brick_stairs"; + materials[110] = "minecraft:mycelium"; + materials[111] = "minecraft:waterlily"; + materials[112] = "minecraft:nether_brick"; + materials[113] = "minecraft:nether_brick_fence"; + materials[114] = "minecraft:nether_brick_stairs"; + materials[116] = "minecraft:enchanting_table"; + materials[119] = "minecraft:end_portal"; + materials[120] = "minecraft:end_portal_frame"; + materials[121] = "minecraft:end_stone"; + materials[122] = "minecraft:dragon_egg"; + materials[123] = "minecraft:redstone_lamp"; + materials[125] = "minecraft:double_wooden_slab"; + materials[126] = "minecraft:wooden_slab"; + materials[127] = "minecraft:cocoa"; + materials[128] = "minecraft:sandstone_stairs"; + materials[129] = "minecraft:emerald_ore"; + materials[130] = "minecraft:ender_chest"; + materials[131] = "minecraft:tripwire_hook"; + materials[133] = "minecraft:emerald_block"; + materials[134] = "minecraft:spruce_stairs"; + materials[135] = "minecraft:birch_stairs"; + materials[136] = "minecraft:jungle_stairs"; + materials[137] = "minecraft:command_block"; + materials[138] = "minecraft:beacon"; + materials[139] = "minecraft:cobblestone_wall"; + materials[141] = "minecraft:carrots"; + materials[142] = "minecraft:potatoes"; + materials[143] = "minecraft:wooden_button"; + materials[145] = "minecraft:anvil"; + materials[146] = "minecraft:trapped_chest"; + materials[147] = "minecraft:light_weighted_pressure_plate"; + materials[148] = "minecraft:heavy_weighted_pressure_plate"; + materials[151] = "minecraft:daylight_detector"; + materials[152] = "minecraft:redstone_block"; + materials[153] = "minecraft:quartz_ore"; + materials[154] = "minecraft:hopper"; + materials[155] = "minecraft:quartz_block"; + materials[156] = "minecraft:quartz_stairs"; + materials[157] = "minecraft:activator_rail"; + materials[158] = "minecraft:dropper"; + materials[159] = "minecraft:stained_hardened_clay"; + materials[160] = "minecraft:stained_glass_pane"; + materials[161] = "minecraft:leaves2"; + materials[162] = "minecraft:log2"; + materials[163] = "minecraft:acacia_stairs"; + materials[164] = "minecraft:dark_oak_stairs"; + materials[170] = "minecraft:hay_block"; + materials[171] = "minecraft:carpet"; + materials[172] = "minecraft:hardened_clay"; + materials[173] = "minecraft:coal_block"; + materials[174] = "minecraft:packed_ice"; + materials[175] = "minecraft:double_plant"; + materials[256] = "minecraft:iron_shovel"; + materials[257] = "minecraft:iron_pickaxe"; + materials[258] = "minecraft:iron_axe"; + materials[259] = "minecraft:flint_and_steel"; + materials[260] = "minecraft:apple"; + materials[261] = "minecraft:bow"; + materials[262] = "minecraft:arrow"; + materials[263] = "minecraft:coal"; + materials[264] = "minecraft:diamond"; + materials[265] = "minecraft:iron_ingot"; + materials[266] = "minecraft:gold_ingot"; + materials[267] = "minecraft:iron_sword"; + materials[268] = "minecraft:wooden_sword"; + materials[269] = "minecraft:wooden_shovel"; + materials[270] = "minecraft:wooden_pickaxe"; + materials[271] = "minecraft:wooden_axe"; + materials[272] = "minecraft:stone_sword"; + materials[273] = "minecraft:stone_shovel"; + materials[274] = "minecraft:stone_pickaxe"; + materials[275] = "minecraft:stone_axe"; + materials[276] = "minecraft:diamond_sword"; + materials[277] = "minecraft:diamond_shovel"; + materials[278] = "minecraft:diamond_pickaxe"; + materials[279] = "minecraft:diamond_axe"; + materials[280] = "minecraft:stick"; + materials[281] = "minecraft:bowl"; + materials[282] = "minecraft:mushroom_stew"; + materials[283] = "minecraft:golden_sword"; + materials[284] = "minecraft:golden_shovel"; + materials[285] = "minecraft:golden_pickaxe"; + materials[286] = "minecraft:golden_axe"; + materials[287] = "minecraft:string"; + materials[288] = "minecraft:feather"; + materials[289] = "minecraft:gunpowder"; + materials[290] = "minecraft:wooden_hoe"; + materials[291] = "minecraft:stone_hoe"; + materials[292] = "minecraft:iron_hoe"; + materials[293] = "minecraft:diamond_hoe"; + materials[294] = "minecraft:golden_hoe"; + materials[295] = "minecraft:wheat_seeds"; + materials[296] = "minecraft:wheat"; + materials[297] = "minecraft:bread"; + materials[298] = "minecraft:leather_helmet"; + materials[299] = "minecraft:leather_chestplate"; + materials[300] = "minecraft:leather_leggings"; + materials[301] = "minecraft:leather_boots"; + materials[302] = "minecraft:chainmail_helmet"; + materials[303] = "minecraft:chainmail_chestplate"; + materials[304] = "minecraft:chainmail_leggings"; + materials[305] = "minecraft:chainmail_boots"; + materials[306] = "minecraft:iron_helmet"; + materials[307] = "minecraft:iron_chestplate"; + materials[308] = "minecraft:iron_leggings"; + materials[309] = "minecraft:iron_boots"; + materials[310] = "minecraft:diamond_helmet"; + materials[311] = "minecraft:diamond_chestplate"; + materials[312] = "minecraft:diamond_leggings"; + materials[313] = "minecraft:diamond_boots"; + materials[314] = "minecraft:golden_helmet"; + materials[315] = "minecraft:golden_chestplate"; + materials[316] = "minecraft:golden_leggings"; + materials[317] = "minecraft:golden_boots"; + materials[318] = "minecraft:flint"; + materials[319] = "minecraft:porkchop"; + materials[320] = "minecraft:cooked_porkchop"; + materials[321] = "minecraft:painting"; + materials[322] = "minecraft:golden_apple"; + materials[323] = "minecraft:sign"; + materials[324] = "minecraft:wooden_door"; + materials[325] = "minecraft:bucket"; + materials[326] = "minecraft:water_bucket"; + materials[327] = "minecraft:lava_bucket"; + materials[328] = "minecraft:minecart"; + materials[329] = "minecraft:saddle"; + materials[330] = "minecraft:iron_door"; + materials[331] = "minecraft:redstone"; + materials[332] = "minecraft:snowball"; + materials[333] = "minecraft:boat"; + materials[334] = "minecraft:leather"; + materials[335] = "minecraft:milk_bucket"; + materials[336] = "minecraft:brick"; + materials[337] = "minecraft:clay_ball"; + materials[338] = "minecraft:reeds"; + materials[339] = "minecraft:paper"; + materials[340] = "minecraft:book"; + materials[341] = "minecraft:slime_ball"; + materials[342] = "minecraft:chest_minecart"; + materials[343] = "minecraft:furnace_minecart"; + materials[344] = "minecraft:egg"; + materials[345] = "minecraft:compass"; + materials[346] = "minecraft:fishing_rod"; + materials[347] = "minecraft:clock"; + materials[348] = "minecraft:glowstone_dust"; + materials[349] = "minecraft:fish"; + materials[350] = "minecraft:cooked_fish"; // Paper - cooked_fished -> cooked_fish + materials[351] = "minecraft:dye"; + materials[352] = "minecraft:bone"; + materials[353] = "minecraft:sugar"; + materials[354] = "minecraft:cake"; + materials[355] = "minecraft:bed"; + materials[356] = "minecraft:repeater"; + materials[357] = "minecraft:cookie"; + materials[358] = "minecraft:filled_map"; + materials[359] = "minecraft:shears"; + materials[360] = "minecraft:melon"; + materials[361] = "minecraft:pumpkin_seeds"; + materials[362] = "minecraft:melon_seeds"; + materials[363] = "minecraft:beef"; + materials[364] = "minecraft:cooked_beef"; + materials[365] = "minecraft:chicken"; + materials[366] = "minecraft:cooked_chicken"; + materials[367] = "minecraft:rotten_flesh"; + materials[368] = "minecraft:ender_pearl"; + materials[369] = "minecraft:blaze_rod"; + materials[370] = "minecraft:ghast_tear"; + materials[371] = "minecraft:gold_nugget"; + materials[372] = "minecraft:nether_wart"; + materials[373] = "minecraft:potion"; + materials[374] = "minecraft:glass_bottle"; + materials[375] = "minecraft:spider_eye"; + materials[376] = "minecraft:fermented_spider_eye"; + materials[377] = "minecraft:blaze_powder"; + materials[378] = "minecraft:magma_cream"; + materials[379] = "minecraft:brewing_stand"; + materials[380] = "minecraft:cauldron"; + materials[381] = "minecraft:ender_eye"; + materials[382] = "minecraft:speckled_melon"; + materials[383] = "minecraft:spawn_egg"; + materials[384] = "minecraft:experience_bottle"; + materials[385] = "minecraft:fire_charge"; + materials[386] = "minecraft:writable_book"; + materials[387] = "minecraft:written_book"; + materials[388] = "minecraft:emerald"; + materials[389] = "minecraft:item_frame"; + materials[390] = "minecraft:flower_pot"; + materials[391] = "minecraft:carrot"; + materials[392] = "minecraft:potato"; + materials[393] = "minecraft:baked_potato"; + materials[394] = "minecraft:poisonous_potato"; + materials[395] = "minecraft:map"; + materials[396] = "minecraft:golden_carrot"; + materials[397] = "minecraft:skull"; + materials[398] = "minecraft:carrot_on_a_stick"; + materials[399] = "minecraft:nether_star"; + materials[400] = "minecraft:pumpkin_pie"; + materials[401] = "minecraft:fireworks"; + materials[402] = "minecraft:firework_charge"; + materials[403] = "minecraft:enchanted_book"; + materials[404] = "minecraft:comparator"; + materials[405] = "minecraft:netherbrick"; + materials[406] = "minecraft:quartz"; + materials[407] = "minecraft:tnt_minecart"; + materials[408] = "minecraft:hopper_minecart"; + materials[417] = "minecraft:iron_horse_armor"; + materials[418] = "minecraft:golden_horse_armor"; + materials[419] = "minecraft:diamond_horse_armor"; + materials[420] = "minecraft:lead"; + materials[421] = "minecraft:name_tag"; + materials[422] = "minecraft:command_block_minecart"; + materials[2256] = "minecraft:record_13"; + materials[2257] = "minecraft:record_cat"; + materials[2258] = "minecraft:record_blocks"; + materials[2259] = "minecraft:record_chirp"; + materials[2260] = "minecraft:record_far"; + materials[2261] = "minecraft:record_mall"; + materials[2262] = "minecraft:record_mellohi"; + materials[2263] = "minecraft:record_stal"; + materials[2264] = "minecraft:record_strad"; + materials[2265] = "minecraft:record_ward"; + materials[2266] = "minecraft:record_11"; + materials[2267] = "minecraft:record_wait"; + } + } + + private static class DataConverterArmorStand implements DataConverter { + + DataConverterArmorStand() {} + + public int getDataVersion() { + return 147; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("ArmorStand".equals(cmp.getString("id")) && cmp.getBoolean("Silent") && !cmp.getBoolean("Marker")) { + cmp.remove("Silent"); + } + + return cmp; + } + } + + private static class DataConverterBanner implements DataConverter { + + DataConverterBanner() {} + + public int getDataVersion() { + return 804; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("minecraft:banner".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + NBTTagCompound nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.contains("Base", 99)) { + cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); + if (nbttagcompound1.contains("display", 10)) { + NBTTagCompound nbttagcompound3 = nbttagcompound1.getCompound("display"); + + if (nbttagcompound3.contains("Lore", 9)) { + NBTTagList nbttaglist = nbttagcompound3.getList("Lore", 8); + + if (nbttaglist.size() == 1 && "(+NBT)".equals(nbttaglist.getString(0))) { + return cmp; + } + } + } + + nbttagcompound2.remove("Base"); + if (nbttagcompound2.isEmpty()) { + nbttagcompound1.remove("BlockEntityTag"); + } + + if (nbttagcompound1.isEmpty()) { + cmp.remove("tag"); + } + } + } + } + + return cmp; + } + } + + private static class DataConverterPotionId implements DataConverter { + + private static final String[] potions = new String[128]; + + DataConverterPotionId() {} + + public int getDataVersion() { + return 102; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("minecraft:potion".equals(cmp.getString("id"))) { + NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + short short0 = cmp.getShort("Damage"); + + if (!nbttagcompound1.contains("Potion", 8)) { + String s = DataConverterPotionId.potions[short0 & 127]; + + nbttagcompound1.putString("Potion", s == null ? "minecraft:water" : s); + cmp.put("tag", nbttagcompound1); + if ((short0 & 16384) == 16384) { + cmp.putString("id", "minecraft:splash_potion"); + } + } + + if (short0 != 0) { + cmp.putShort("Damage", (short) 0); + } + } + + return cmp; + } + + static { + DataConverterPotionId.potions[0] = "minecraft:water"; + DataConverterPotionId.potions[1] = "minecraft:regeneration"; + DataConverterPotionId.potions[2] = "minecraft:swiftness"; + DataConverterPotionId.potions[3] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[4] = "minecraft:poison"; + DataConverterPotionId.potions[5] = "minecraft:healing"; + DataConverterPotionId.potions[6] = "minecraft:night_vision"; + DataConverterPotionId.potions[7] = null; + DataConverterPotionId.potions[8] = "minecraft:weakness"; + DataConverterPotionId.potions[9] = "minecraft:strength"; + DataConverterPotionId.potions[10] = "minecraft:slowness"; + DataConverterPotionId.potions[11] = "minecraft:leaping"; + DataConverterPotionId.potions[12] = "minecraft:harming"; + DataConverterPotionId.potions[13] = "minecraft:water_breathing"; + DataConverterPotionId.potions[14] = "minecraft:invisibility"; + DataConverterPotionId.potions[15] = null; + DataConverterPotionId.potions[16] = "minecraft:awkward"; + DataConverterPotionId.potions[17] = "minecraft:regeneration"; + DataConverterPotionId.potions[18] = "minecraft:swiftness"; + DataConverterPotionId.potions[19] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[20] = "minecraft:poison"; + DataConverterPotionId.potions[21] = "minecraft:healing"; + DataConverterPotionId.potions[22] = "minecraft:night_vision"; + DataConverterPotionId.potions[23] = null; + DataConverterPotionId.potions[24] = "minecraft:weakness"; + DataConverterPotionId.potions[25] = "minecraft:strength"; + DataConverterPotionId.potions[26] = "minecraft:slowness"; + DataConverterPotionId.potions[27] = "minecraft:leaping"; + DataConverterPotionId.potions[28] = "minecraft:harming"; + DataConverterPotionId.potions[29] = "minecraft:water_breathing"; + DataConverterPotionId.potions[30] = "minecraft:invisibility"; + DataConverterPotionId.potions[31] = null; + DataConverterPotionId.potions[32] = "minecraft:thick"; + DataConverterPotionId.potions[33] = "minecraft:strong_regeneration"; + DataConverterPotionId.potions[34] = "minecraft:strong_swiftness"; + DataConverterPotionId.potions[35] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[36] = "minecraft:strong_poison"; + DataConverterPotionId.potions[37] = "minecraft:strong_healing"; + DataConverterPotionId.potions[38] = "minecraft:night_vision"; + DataConverterPotionId.potions[39] = null; + DataConverterPotionId.potions[40] = "minecraft:weakness"; + DataConverterPotionId.potions[41] = "minecraft:strong_strength"; + DataConverterPotionId.potions[42] = "minecraft:slowness"; + DataConverterPotionId.potions[43] = "minecraft:strong_leaping"; + DataConverterPotionId.potions[44] = "minecraft:strong_harming"; + DataConverterPotionId.potions[45] = "minecraft:water_breathing"; + DataConverterPotionId.potions[46] = "minecraft:invisibility"; + DataConverterPotionId.potions[47] = null; + DataConverterPotionId.potions[48] = null; + DataConverterPotionId.potions[49] = "minecraft:strong_regeneration"; + DataConverterPotionId.potions[50] = "minecraft:strong_swiftness"; + DataConverterPotionId.potions[51] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[52] = "minecraft:strong_poison"; + DataConverterPotionId.potions[53] = "minecraft:strong_healing"; + DataConverterPotionId.potions[54] = "minecraft:night_vision"; + DataConverterPotionId.potions[55] = null; + DataConverterPotionId.potions[56] = "minecraft:weakness"; + DataConverterPotionId.potions[57] = "minecraft:strong_strength"; + DataConverterPotionId.potions[58] = "minecraft:slowness"; + DataConverterPotionId.potions[59] = "minecraft:strong_leaping"; + DataConverterPotionId.potions[60] = "minecraft:strong_harming"; + DataConverterPotionId.potions[61] = "minecraft:water_breathing"; + DataConverterPotionId.potions[62] = "minecraft:invisibility"; + DataConverterPotionId.potions[63] = null; + DataConverterPotionId.potions[64] = "minecraft:mundane"; + DataConverterPotionId.potions[65] = "minecraft:long_regeneration"; + DataConverterPotionId.potions[66] = "minecraft:long_swiftness"; + DataConverterPotionId.potions[67] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[68] = "minecraft:long_poison"; + DataConverterPotionId.potions[69] = "minecraft:healing"; + DataConverterPotionId.potions[70] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[71] = null; + DataConverterPotionId.potions[72] = "minecraft:long_weakness"; + DataConverterPotionId.potions[73] = "minecraft:long_strength"; + DataConverterPotionId.potions[74] = "minecraft:long_slowness"; + DataConverterPotionId.potions[75] = "minecraft:long_leaping"; + DataConverterPotionId.potions[76] = "minecraft:harming"; + DataConverterPotionId.potions[77] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[78] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[79] = null; + DataConverterPotionId.potions[80] = "minecraft:awkward"; + DataConverterPotionId.potions[81] = "minecraft:long_regeneration"; + DataConverterPotionId.potions[82] = "minecraft:long_swiftness"; + DataConverterPotionId.potions[83] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[84] = "minecraft:long_poison"; + DataConverterPotionId.potions[85] = "minecraft:healing"; + DataConverterPotionId.potions[86] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[87] = null; + DataConverterPotionId.potions[88] = "minecraft:long_weakness"; + DataConverterPotionId.potions[89] = "minecraft:long_strength"; + DataConverterPotionId.potions[90] = "minecraft:long_slowness"; + DataConverterPotionId.potions[91] = "minecraft:long_leaping"; + DataConverterPotionId.potions[92] = "minecraft:harming"; + DataConverterPotionId.potions[93] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[94] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[95] = null; + DataConverterPotionId.potions[96] = "minecraft:thick"; + DataConverterPotionId.potions[97] = "minecraft:regeneration"; + DataConverterPotionId.potions[98] = "minecraft:swiftness"; + DataConverterPotionId.potions[99] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[100] = "minecraft:poison"; + DataConverterPotionId.potions[101] = "minecraft:strong_healing"; + DataConverterPotionId.potions[102] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[103] = null; + DataConverterPotionId.potions[104] = "minecraft:long_weakness"; + DataConverterPotionId.potions[105] = "minecraft:strength"; + DataConverterPotionId.potions[106] = "minecraft:long_slowness"; + DataConverterPotionId.potions[107] = "minecraft:leaping"; + DataConverterPotionId.potions[108] = "minecraft:strong_harming"; + DataConverterPotionId.potions[109] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[110] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[111] = null; + DataConverterPotionId.potions[112] = null; + DataConverterPotionId.potions[113] = "minecraft:regeneration"; + DataConverterPotionId.potions[114] = "minecraft:swiftness"; + DataConverterPotionId.potions[115] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[116] = "minecraft:poison"; + DataConverterPotionId.potions[117] = "minecraft:strong_healing"; + DataConverterPotionId.potions[118] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[119] = null; + DataConverterPotionId.potions[120] = "minecraft:long_weakness"; + DataConverterPotionId.potions[121] = "minecraft:strength"; + DataConverterPotionId.potions[122] = "minecraft:long_slowness"; + DataConverterPotionId.potions[123] = "minecraft:leaping"; + DataConverterPotionId.potions[124] = "minecraft:strong_harming"; + DataConverterPotionId.potions[125] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[126] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[127] = null; + } + } + + private static class DataConverterSpawnEgg implements DataConverter { + + private static final String[] eggs = new String[256]; + + DataConverterSpawnEgg() {} + + public int getDataVersion() { + return 105; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("minecraft:spawn_egg".equals(cmp.getString("id"))) { + NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + NBTTagCompound nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + short short0 = cmp.getShort("Damage"); + + if (!nbttagcompound2.contains("id", 8)) { + String s = DataConverterSpawnEgg.eggs[short0 & 255]; + + if (s != null) { + nbttagcompound2.putString("id", s); + nbttagcompound1.put("EntityTag", nbttagcompound2); + cmp.put("tag", nbttagcompound1); + } + } + + if (short0 != 0) { + cmp.putShort("Damage", (short) 0); + } + } + + return cmp; + } + + static { + + DataConverterSpawnEgg.eggs[1] = "Item"; + DataConverterSpawnEgg.eggs[2] = "XPOrb"; + DataConverterSpawnEgg.eggs[7] = "ThrownEgg"; + DataConverterSpawnEgg.eggs[8] = "LeashKnot"; + DataConverterSpawnEgg.eggs[9] = "Painting"; + DataConverterSpawnEgg.eggs[10] = "Arrow"; + DataConverterSpawnEgg.eggs[11] = "Snowball"; + DataConverterSpawnEgg.eggs[12] = "Fireball"; + DataConverterSpawnEgg.eggs[13] = "SmallFireball"; + DataConverterSpawnEgg.eggs[14] = "ThrownEnderpearl"; + DataConverterSpawnEgg.eggs[15] = "EyeOfEnderSignal"; + DataConverterSpawnEgg.eggs[16] = "ThrownPotion"; + DataConverterSpawnEgg.eggs[17] = "ThrownExpBottle"; + DataConverterSpawnEgg.eggs[18] = "ItemFrame"; + DataConverterSpawnEgg.eggs[19] = "WitherSkull"; + DataConverterSpawnEgg.eggs[20] = "PrimedTnt"; + DataConverterSpawnEgg.eggs[21] = "FallingSand"; + DataConverterSpawnEgg.eggs[22] = "FireworksRocketEntity"; + DataConverterSpawnEgg.eggs[23] = "TippedArrow"; + DataConverterSpawnEgg.eggs[24] = "SpectralArrow"; + DataConverterSpawnEgg.eggs[25] = "ShulkerBullet"; + DataConverterSpawnEgg.eggs[26] = "DragonFireball"; + DataConverterSpawnEgg.eggs[30] = "ArmorStand"; + DataConverterSpawnEgg.eggs[41] = "Boat"; + DataConverterSpawnEgg.eggs[42] = "MinecartRideable"; + DataConverterSpawnEgg.eggs[43] = "MinecartChest"; + DataConverterSpawnEgg.eggs[44] = "MinecartFurnace"; + DataConverterSpawnEgg.eggs[45] = "MinecartTNT"; + DataConverterSpawnEgg.eggs[46] = "MinecartHopper"; + DataConverterSpawnEgg.eggs[47] = "MinecartSpawner"; + DataConverterSpawnEgg.eggs[40] = "MinecartCommandBlock"; + DataConverterSpawnEgg.eggs[48] = "Mob"; + DataConverterSpawnEgg.eggs[49] = "Monster"; + DataConverterSpawnEgg.eggs[50] = "Creeper"; + DataConverterSpawnEgg.eggs[51] = "Skeleton"; + DataConverterSpawnEgg.eggs[52] = "Spider"; + DataConverterSpawnEgg.eggs[53] = "Giant"; + DataConverterSpawnEgg.eggs[54] = "Zombie"; + DataConverterSpawnEgg.eggs[55] = "Slime"; + DataConverterSpawnEgg.eggs[56] = "Ghast"; + DataConverterSpawnEgg.eggs[57] = "PigZombie"; + DataConverterSpawnEgg.eggs[58] = "Enderman"; + DataConverterSpawnEgg.eggs[59] = "CaveSpider"; + DataConverterSpawnEgg.eggs[60] = "Silverfish"; + DataConverterSpawnEgg.eggs[61] = "Blaze"; + DataConverterSpawnEgg.eggs[62] = "LavaSlime"; + DataConverterSpawnEgg.eggs[63] = "EnderDragon"; + DataConverterSpawnEgg.eggs[64] = "WitherBoss"; + DataConverterSpawnEgg.eggs[65] = "Bat"; + DataConverterSpawnEgg.eggs[66] = "Witch"; + DataConverterSpawnEgg.eggs[67] = "Endermite"; + DataConverterSpawnEgg.eggs[68] = "Guardian"; + DataConverterSpawnEgg.eggs[69] = "Shulker"; + DataConverterSpawnEgg.eggs[90] = "Pig"; + DataConverterSpawnEgg.eggs[91] = "Sheep"; + DataConverterSpawnEgg.eggs[92] = "Cow"; + DataConverterSpawnEgg.eggs[93] = "Chicken"; + DataConverterSpawnEgg.eggs[94] = "Squid"; + DataConverterSpawnEgg.eggs[95] = "Wolf"; + DataConverterSpawnEgg.eggs[96] = "MushroomCow"; + DataConverterSpawnEgg.eggs[97] = "SnowMan"; + DataConverterSpawnEgg.eggs[98] = "Ozelot"; + DataConverterSpawnEgg.eggs[99] = "VillagerGolem"; + DataConverterSpawnEgg.eggs[100] = "EntityHorse"; + DataConverterSpawnEgg.eggs[101] = "Rabbit"; + DataConverterSpawnEgg.eggs[120] = "Villager"; + DataConverterSpawnEgg.eggs[200] = "EnderCrystal"; + } + } + + private static class DataConverterMinecart implements DataConverter { + + private static final List a = Lists.newArrayList(new String[] { "MinecartRideable", "MinecartChest", "MinecartFurnace", "MinecartTNT", "MinecartSpawner", "MinecartHopper", "MinecartCommandBlock"}); + + DataConverterMinecart() {} + + public int getDataVersion() { + return 106; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("Minecart".equals(cmp.getString("id"))) { + String s = "MinecartRideable"; + int i = cmp.getInt("Type"); + + if (i > 0 && i < DataConverterMinecart.a.size()) { + s = DataConverterMinecart.a.get(i); + } + + cmp.putString("id", s); + cmp.remove("Type"); + } + + return cmp; + } + } + + private static class DataConverterMobSpawner implements DataConverter { + + DataConverterMobSpawner() {} + + public int getDataVersion() { + return 107; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if (!"MobSpawner".equals(cmp.getString("id"))) { + return cmp; + } else { + if (cmp.contains("EntityId", 8)) { + String s = cmp.getString("EntityId"); + NBTTagCompound nbttagcompound1 = cmp.getCompound("SpawnData"); + + nbttagcompound1.putString("id", s.isEmpty() ? "Pig" : s); + cmp.put("SpawnData", nbttagcompound1); + cmp.remove("EntityId"); + } + + if (cmp.contains("SpawnPotentials", 9)) { + NBTTagList nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int i = 0; i < nbttaglist.size(); ++i) { + NBTTagCompound nbttagcompound2 = nbttaglist.getCompound(i); + + if (nbttagcompound2.contains("Type", 8)) { + NBTTagCompound nbttagcompound3 = nbttagcompound2.getCompound("Properties"); + + nbttagcompound3.putString("id", nbttagcompound2.getString("Type")); + nbttagcompound2.put("Entity", nbttagcompound3); + nbttagcompound2.remove("Type"); + nbttagcompound2.remove("Properties"); + } + } + } + + return cmp; + } + } + } + + private static class DataConverterUUID implements DataConverter { + + DataConverterUUID() {} + + public int getDataVersion() { + return 108; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if (cmp.contains("UUID", 8)) { + cmp.putUniqueId("UUID", UUID.fromString(cmp.getString("UUID"))); + } + + return cmp; + } + } + + private static class DataConverterHealth implements DataConverter { + + private static final Set a = Sets.newHashSet(new String[] { "ArmorStand", "Bat", "Blaze", "CaveSpider", "Chicken", "Cow", "Creeper", "EnderDragon", "Enderman", "Endermite", "EntityHorse", "Ghast", "Giant", "Guardian", "LavaSlime", "MushroomCow", "Ozelot", "Pig", "PigZombie", "Rabbit", "Sheep", "Shulker", "Silverfish", "Skeleton", "Slime", "SnowMan", "Spider", "Squid", "Villager", "VillagerGolem", "Witch", "WitherBoss", "Wolf", "Zombie"}); + + DataConverterHealth() {} + + public int getDataVersion() { + return 109; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if (DataConverterHealth.a.contains(cmp.getString("id"))) { + float f; + + if (cmp.contains("HealF", 99)) { + f = cmp.getFloat("HealF"); + cmp.remove("HealF"); + } else { + if (!cmp.contains("Health", 99)) { + return cmp; + } + + f = cmp.getFloat("Health"); + } + + cmp.putFloat("Health", f); + } + + return cmp; + } + } + + private static class DataConverterSaddle implements DataConverter { + + DataConverterSaddle() {} + + public int getDataVersion() { + return 110; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("SaddleItem", 10) && cmp.getBoolean("Saddle")) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + + nbttagcompound1.putString("id", "minecraft:saddle"); + nbttagcompound1.putByte("Count", (byte) 1); + nbttagcompound1.putShort("Damage", (short) 0); + cmp.put("SaddleItem", nbttagcompound1); + cmp.remove("Saddle"); + } + + return cmp; + } + } + + private static class DataConverterHanging implements DataConverter { + + DataConverterHanging() {} + + public int getDataVersion() { + return 111; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + String s = cmp.getString("id"); + boolean flag = "Painting".equals(s); + boolean flag1 = "ItemFrame".equals(s); + + if ((flag || flag1) && !cmp.contains("Facing", 99)) { + EnumFacing enumdirection; + + if (cmp.contains("Direction", 99)) { + enumdirection = EnumFacing.byHorizontalIndex(cmp.getByte("Direction")); + cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getXOffset()); + cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getYOffset()); + cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getZOffset()); + cmp.remove("Direction"); + if (flag1 && cmp.contains("ItemRotation", 99)) { + cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); + } + } else { + enumdirection = EnumFacing.byHorizontalIndex(cmp.getByte("Dir")); + cmp.remove("Dir"); + } + + cmp.putByte("Facing", (byte) enumdirection.getHorizontalIndex()); + } + + return cmp; + } + } + + private static class DataConverterDropChances implements DataConverter { + + DataConverterDropChances() {} + + public int getDataVersion() { + return 113; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + NBTTagList nbttaglist; + + if (cmp.contains("HandDropChances", 9)) { + nbttaglist = cmp.getList("HandDropChances", 5); + if (nbttaglist.size() == 2 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F) { + cmp.remove("HandDropChances"); + } + } + + if (cmp.contains("ArmorDropChances", 9)) { + nbttaglist = cmp.getList("ArmorDropChances", 5); + if (nbttaglist.size() == 4 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F && nbttaglist.getFloat(2) == 0.0F && nbttaglist.getFloat(3) == 0.0F) { + cmp.remove("ArmorDropChances"); + } + } + + return cmp; + } + } + + private static class DataConverterRiding implements DataConverter { + + DataConverterRiding() {} + + public int getDataVersion() { + return 135; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + while (cmp.contains("Riding", 10)) { + NBTTagCompound nbttagcompound1 = this.b(cmp); + + this.convert(cmp, nbttagcompound1); + cmp = nbttagcompound1; + } + + return cmp; + } + + protected void convert(NBTTagCompound nbttagcompound, NBTTagCompound nbttagcompound1) { + NBTTagList nbttaglist = new NBTTagList(); + + nbttaglist.add(nbttagcompound); + nbttagcompound1.put("Passengers", nbttaglist); + } + + protected NBTTagCompound b(NBTTagCompound nbttagcompound) { + NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("Riding"); + + nbttagcompound.remove("Riding"); + return nbttagcompound1; + } + } + + private static class DataConverterBook implements DataConverter { + + DataConverterBook() {} + + public int getDataVersion() { + return 165; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("minecraft:written_book".equals(cmp.getString("id"))) { + NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("pages", 9)) { + NBTTagList nbttaglist = nbttagcompound1.getList("pages", 8); + + for (int i = 0; i < nbttaglist.size(); ++i) { + String s = nbttaglist.getString(i); + Object object = null; + + if (!"null".equals(s) && !StringUtils.isNullOrEmpty(s)) { + if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { + object = new TextComponentString(s); + } else { + try { + object = JsonUtils.fromJson(DataConverterSignText.a, s, ITextComponent.class, true); + if (object == null) { + object = new TextComponentString(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = ITextComponent.Serializer.fromJson(s); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = ITextComponent.Serializer.fromJsonLenient(s); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = new TextComponentString(s); + } + } + } else { + object = new TextComponentString(""); + } + + nbttaglist.set(i, new NBTTagString(ITextComponent.Serializer.toJson((ITextComponent) object))); + } + + nbttagcompound1.put("pages", nbttaglist); + } + } + + return cmp; + } + } + + private static class DataConverterCookedFish implements DataConverter { + + private static final ResourceLocation a = new ResourceLocation("cooked_fished"); + + DataConverterCookedFish() {} + + public int getDataVersion() { + return 502; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if (cmp.contains("id", 8) && DataConverterCookedFish.a.equals(new ResourceLocation(cmp.getString("id")))) { + cmp.putString("id", "minecraft:cooked_fish"); + } + + return cmp; + } + } + + private static class DataConverterZombie implements DataConverter { + + private static final Random a = new Random(); + + DataConverterZombie() {} + + public int getDataVersion() { + return 502; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("Zombie".equals(cmp.getString("id")) && cmp.getBoolean("IsVillager")) { + if (!cmp.contains("ZombieType", 99)) { + int i = -1; + + if (cmp.contains("VillagerProfession", 99)) { + try { + i = this.convert(cmp.getInt("VillagerProfession")); + } catch (RuntimeException runtimeexception) { + ; + } + } + + if (i == -1) { + i = this.convert(DataConverterZombie.a.nextInt(6)); + } + + cmp.putInt("ZombieType", i); + } + + cmp.remove("IsVillager"); + } + + return cmp; + } + + private int convert(int i) { + return i >= 0 && i < 6 ? i : -1; + } + } + + private static class DataConverterVBO implements DataConverter { + + DataConverterVBO() {} + + public int getDataVersion() { + return 505; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + cmp.putString("useVbo", "true"); + return cmp; + } + } + + private static class DataConverterGuardian implements DataConverter { + + DataConverterGuardian() {} + + public int getDataVersion() { + return 700; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("Guardian".equals(cmp.getString("id"))) { + if (cmp.getBoolean("Elder")) { + cmp.putString("id", "ElderGuardian"); + } + + cmp.remove("Elder"); + } + + return cmp; + } + } + + private static class DataConverterSkeleton implements DataConverter { + + DataConverterSkeleton() {} + + public int getDataVersion() { + return 701; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + String s = cmp.getString("id"); + + if ("Skeleton".equals(s)) { + int i = cmp.getInt("SkeletonType"); + + if (i == 1) { + cmp.putString("id", "WitherSkeleton"); + } else if (i == 2) { + cmp.putString("id", "Stray"); + } + + cmp.remove("SkeletonType"); + } + + return cmp; + } + } + + private static class DataConverterZombieType implements DataConverter { + + DataConverterZombieType() {} + + public int getDataVersion() { + return 702; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("Zombie".equals(cmp.getString("id"))) { + int i = cmp.getInt("ZombieType"); + + switch (i) { + case 1: + case 2: + case 3: + case 4: + case 5: + cmp.putString("id", "ZombieVillager"); + cmp.putInt("Profession", i - 1); + break; + case 6: + cmp.putString("id", "Husk"); + case 0: + default: + break; + } + + cmp.remove("ZombieType"); + } + + return cmp; + } + } + + private static class DataConverterHorse implements DataConverter { + + DataConverterHorse() {} + + public int getDataVersion() { + return 703; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("EntityHorse".equals(cmp.getString("id"))) { + int i = cmp.getInt("Type"); + + switch (i) { + case 1: + cmp.putString("id", "Donkey"); + break; + + case 2: + cmp.putString("id", "Mule"); + break; + + case 3: + cmp.putString("id", "ZombieHorse"); + break; + + case 4: + cmp.putString("id", "SkeletonHorse"); + break; + + case 0: + default: + cmp.putString("id", "Horse"); + break; + } + + cmp.remove("Type"); + } + + return cmp; + } + } + + private static class DataConverterTileEntity implements DataConverter { + + private static final Map a = Maps.newHashMap(); + + DataConverterTileEntity() {} + + public int getDataVersion() { + return 704; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + String s = DataConverterTileEntity.a.get(cmp.getString("id")); + + if (s != null) { + cmp.putString("id", s); + } + + return cmp; + } + + static { + DataConverterTileEntity.a.put("Airportal", "minecraft:end_portal"); + DataConverterTileEntity.a.put("Banner", "minecraft:banner"); + DataConverterTileEntity.a.put("Beacon", "minecraft:beacon"); + DataConverterTileEntity.a.put("Cauldron", "minecraft:brewing_stand"); + DataConverterTileEntity.a.put("Chest", "minecraft:chest"); + DataConverterTileEntity.a.put("Comparator", "minecraft:comparator"); + DataConverterTileEntity.a.put("Control", "minecraft:command_block"); + DataConverterTileEntity.a.put("DLDetector", "minecraft:daylight_detector"); + DataConverterTileEntity.a.put("Dropper", "minecraft:dropper"); + DataConverterTileEntity.a.put("EnchantTable", "minecraft:enchanting_table"); + DataConverterTileEntity.a.put("EndGateway", "minecraft:end_gateway"); + DataConverterTileEntity.a.put("EnderChest", "minecraft:ender_chest"); + DataConverterTileEntity.a.put("FlowerPot", "minecraft:flower_pot"); + DataConverterTileEntity.a.put("Furnace", "minecraft:furnace"); + DataConverterTileEntity.a.put("Hopper", "minecraft:hopper"); + DataConverterTileEntity.a.put("MobSpawner", "minecraft:mob_spawner"); + DataConverterTileEntity.a.put("Music", "minecraft:noteblock"); + DataConverterTileEntity.a.put("Piston", "minecraft:piston"); + DataConverterTileEntity.a.put("RecordPlayer", "minecraft:jukebox"); + DataConverterTileEntity.a.put("Sign", "minecraft:sign"); + DataConverterTileEntity.a.put("Skull", "minecraft:skull"); + DataConverterTileEntity.a.put("Structure", "minecraft:structure_block"); + DataConverterTileEntity.a.put("Trap", "minecraft:dispenser"); + } + } + + private static class DataConverterEntity implements DataConverter { + + private static final Map a = Maps.newHashMap(); + + DataConverterEntity() {} + + public int getDataVersion() { + return 704; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + String s = DataConverterEntity.a.get(cmp.getString("id")); + + if (s != null) { + cmp.putString("id", s); + } + + return cmp; + } + + static { + DataConverterEntity.a.put("AreaEffectCloud", "minecraft:area_effect_cloud"); + DataConverterEntity.a.put("ArmorStand", "minecraft:armor_stand"); + DataConverterEntity.a.put("Arrow", "minecraft:arrow"); + DataConverterEntity.a.put("Bat", "minecraft:bat"); + DataConverterEntity.a.put("Blaze", "minecraft:blaze"); + DataConverterEntity.a.put("Boat", "minecraft:boat"); + DataConverterEntity.a.put("CaveSpider", "minecraft:cave_spider"); + DataConverterEntity.a.put("Chicken", "minecraft:chicken"); + DataConverterEntity.a.put("Cow", "minecraft:cow"); + DataConverterEntity.a.put("Creeper", "minecraft:creeper"); + DataConverterEntity.a.put("Donkey", "minecraft:donkey"); + DataConverterEntity.a.put("DragonFireball", "minecraft:dragon_fireball"); + DataConverterEntity.a.put("ElderGuardian", "minecraft:elder_guardian"); + DataConverterEntity.a.put("EnderCrystal", "minecraft:ender_crystal"); + DataConverterEntity.a.put("EnderDragon", "minecraft:ender_dragon"); + DataConverterEntity.a.put("Enderman", "minecraft:enderman"); + DataConverterEntity.a.put("Endermite", "minecraft:endermite"); + DataConverterEntity.a.put("EyeOfEnderSignal", "minecraft:eye_of_ender_signal"); + DataConverterEntity.a.put("FallingSand", "minecraft:falling_block"); + DataConverterEntity.a.put("Fireball", "minecraft:fireball"); + DataConverterEntity.a.put("FireworksRocketEntity", "minecraft:fireworks_rocket"); + DataConverterEntity.a.put("Ghast", "minecraft:ghast"); + DataConverterEntity.a.put("Giant", "minecraft:giant"); + DataConverterEntity.a.put("Guardian", "minecraft:guardian"); + DataConverterEntity.a.put("Horse", "minecraft:horse"); + DataConverterEntity.a.put("Husk", "minecraft:husk"); + DataConverterEntity.a.put("Item", "minecraft:item"); + DataConverterEntity.a.put("ItemFrame", "minecraft:item_frame"); + DataConverterEntity.a.put("LavaSlime", "minecraft:magma_cube"); + DataConverterEntity.a.put("LeashKnot", "minecraft:leash_knot"); + DataConverterEntity.a.put("MinecartChest", "minecraft:chest_minecart"); + DataConverterEntity.a.put("MinecartCommandBlock", "minecraft:commandblock_minecart"); + DataConverterEntity.a.put("MinecartFurnace", "minecraft:furnace_minecart"); + DataConverterEntity.a.put("MinecartHopper", "minecraft:hopper_minecart"); + DataConverterEntity.a.put("MinecartRideable", "minecraft:minecart"); + DataConverterEntity.a.put("MinecartSpawner", "minecraft:spawner_minecart"); + DataConverterEntity.a.put("MinecartTNT", "minecraft:tnt_minecart"); + DataConverterEntity.a.put("Mule", "minecraft:mule"); + DataConverterEntity.a.put("MushroomCow", "minecraft:mooshroom"); + DataConverterEntity.a.put("Ozelot", "minecraft:ocelot"); + DataConverterEntity.a.put("Painting", "minecraft:painting"); + DataConverterEntity.a.put("Pig", "minecraft:pig"); + DataConverterEntity.a.put("PigZombie", "minecraft:zombie_pigman"); + DataConverterEntity.a.put("PolarBear", "minecraft:polar_bear"); + DataConverterEntity.a.put("PrimedTnt", "minecraft:tnt"); + DataConverterEntity.a.put("Rabbit", "minecraft:rabbit"); + DataConverterEntity.a.put("Sheep", "minecraft:sheep"); + DataConverterEntity.a.put("Shulker", "minecraft:shulker"); + DataConverterEntity.a.put("ShulkerBullet", "minecraft:shulker_bullet"); + DataConverterEntity.a.put("Silverfish", "minecraft:silverfish"); + DataConverterEntity.a.put("Skeleton", "minecraft:skeleton"); + DataConverterEntity.a.put("SkeletonHorse", "minecraft:skeleton_horse"); + DataConverterEntity.a.put("Slime", "minecraft:slime"); + DataConverterEntity.a.put("SmallFireball", "minecraft:small_fireball"); + DataConverterEntity.a.put("SnowMan", "minecraft:snowman"); + DataConverterEntity.a.put("Snowball", "minecraft:snowball"); + DataConverterEntity.a.put("SpectralArrow", "minecraft:spectral_arrow"); + DataConverterEntity.a.put("Spider", "minecraft:spider"); + DataConverterEntity.a.put("Squid", "minecraft:squid"); + DataConverterEntity.a.put("Stray", "minecraft:stray"); + DataConverterEntity.a.put("ThrownEgg", "minecraft:egg"); + DataConverterEntity.a.put("ThrownEnderpearl", "minecraft:ender_pearl"); + DataConverterEntity.a.put("ThrownExpBottle", "minecraft:xp_bottle"); + DataConverterEntity.a.put("ThrownPotion", "minecraft:potion"); + DataConverterEntity.a.put("Villager", "minecraft:villager"); + DataConverterEntity.a.put("VillagerGolem", "minecraft:villager_golem"); + DataConverterEntity.a.put("Witch", "minecraft:witch"); + DataConverterEntity.a.put("WitherBoss", "minecraft:wither"); + DataConverterEntity.a.put("WitherSkeleton", "minecraft:wither_skeleton"); + DataConverterEntity.a.put("WitherSkull", "minecraft:wither_skull"); + DataConverterEntity.a.put("Wolf", "minecraft:wolf"); + DataConverterEntity.a.put("XPOrb", "minecraft:xp_orb"); + DataConverterEntity.a.put("Zombie", "minecraft:zombie"); + DataConverterEntity.a.put("ZombieHorse", "minecraft:zombie_horse"); + DataConverterEntity.a.put("ZombieVillager", "minecraft:zombie_villager"); + } + } + + private static class DataConverterPotionWater implements DataConverter { + + DataConverterPotionWater() {} + + public int getDataVersion() { + return 806; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + String s = cmp.getString("id"); + + if ("minecraft:potion".equals(s) || "minecraft:splash_potion".equals(s) || "minecraft:lingering_potion".equals(s) || "minecraft:tipped_arrow".equals(s)) { + NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + + if (!nbttagcompound1.contains("Potion", 8)) { + nbttagcompound1.putString("Potion", "minecraft:water"); + } + + if (!cmp.contains("tag", 10)) { + cmp.put("tag", nbttagcompound1); + } + } + + return cmp; + } + } + + private static class DataConverterShulker implements DataConverter { + + DataConverterShulker() {} + + public int getDataVersion() { + return 808; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("minecraft:shulker".equals(cmp.getString("id")) && !cmp.contains("Color", 99)) { + cmp.putByte("Color", (byte) 10); + } + + return cmp; + } + } + + private static class DataConverterShulkerBoxItem implements DataConverter { + + public static final String[] a = new String[] { "minecraft:white_shulker_box", "minecraft:orange_shulker_box", "minecraft:magenta_shulker_box", "minecraft:light_blue_shulker_box", "minecraft:yellow_shulker_box", "minecraft:lime_shulker_box", "minecraft:pink_shulker_box", "minecraft:gray_shulker_box", "minecraft:silver_shulker_box", "minecraft:cyan_shulker_box", "minecraft:purple_shulker_box", "minecraft:blue_shulker_box", "minecraft:brown_shulker_box", "minecraft:green_shulker_box", "minecraft:red_shulker_box", "minecraft:black_shulker_box"}; + + DataConverterShulkerBoxItem() {} + + public int getDataVersion() { + return 813; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { + NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.contains("BlockEntityTag", 10)) { + NBTTagCompound nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.getList("Items", 10).isEmpty()) { + nbttagcompound2.remove("Items"); + } + + int i = nbttagcompound2.getInt("Color"); + + nbttagcompound2.remove("Color"); + if (nbttagcompound2.isEmpty()) { + nbttagcompound1.remove("BlockEntityTag"); + } + + if (nbttagcompound1.isEmpty()) { + cmp.remove("tag"); + } + + cmp.putString("id", DataConverterShulkerBoxItem.a[i % 16]); + } + } + + return cmp; + } + } + + private static class DataConverterShulkerBoxBlock implements DataConverter { + + DataConverterShulkerBoxBlock() {} + + public int getDataVersion() { + return 813; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("minecraft:shulker".equals(cmp.getString("id"))) { + cmp.remove("Color"); + } + + return cmp; + } + } + + private static class DataConverterLang implements DataConverter { + + DataConverterLang() {} + + public int getDataVersion() { + return 816; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if (cmp.contains("lang", 8)) { + cmp.putString("lang", cmp.getString("lang").toLowerCase(Locale.ROOT)); + } + + return cmp; + } + } + + private static class DataConverterTotem implements DataConverter { + + DataConverterTotem() {} + + public int getDataVersion() { + return 820; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("minecraft:totem".equals(cmp.getString("id"))) { + cmp.putString("id", "minecraft:totem_of_undying"); + } + + return cmp; + } + } + + private static class DataConverterBedBlock implements DataConverter { + + private static final Logger a = LogManager.getLogger(ForgeDataFixer.class); + + DataConverterBedBlock() {} + + public int getDataVersion() { + return 1125; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + boolean flag = true; + + try { + NBTTagCompound nbttagcompound1 = cmp.getCompound("Level"); + int i = nbttagcompound1.getInt("xPos"); + int j = nbttagcompound1.getInt("zPos"); + NBTTagList nbttaglist = nbttagcompound1.getList("TileEntities", 10); + NBTTagList nbttaglist1 = nbttagcompound1.getList("Sections", 10); + + for (int k = 0; k < nbttaglist1.size(); ++k) { + NBTTagCompound nbttagcompound2 = nbttaglist1.getCompound(k); + byte b0 = nbttagcompound2.getByte("Y"); + byte[] abyte = nbttagcompound2.getByteArray("Blocks"); + + for (int l = 0; l < abyte.length; ++l) { + if (416 == (abyte[l] & 255) << 4) { + int i1 = l & 15; + int j1 = l >> 8 & 15; + int k1 = l >> 4 & 15; + NBTTagCompound nbttagcompound3 = new NBTTagCompound(); + + nbttagcompound3.putString("id", "bed"); + nbttagcompound3.putInt("x", i1 + (i << 4)); + nbttagcompound3.putInt("y", j1 + (b0 << 4)); + nbttagcompound3.putInt("z", k1 + (j << 4)); + nbttaglist.add(nbttagcompound3); + } + } + } + } catch (Exception exception) { + DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); + } + + return cmp; + } + } + + private static class DataConverterBedItem implements DataConverter { + + DataConverterBedItem() {} + + public int getDataVersion() { + return 1125; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { + cmp.putShort("Damage", (short) EnumDyeColor.RED.getId()); + } + + return cmp; + } + } + + private static class DataConverterSignText implements DataConverter { + + public static final Gson a = new GsonBuilder().registerTypeAdapter(ITextComponent.class, new JsonDeserializer() { + ITextComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + if (jsonelement.isJsonPrimitive()) { + return new TextComponentString(jsonelement.getAsString()); + } else if (jsonelement.isJsonArray()) { + JsonArray jsonarray = jsonelement.getAsJsonArray(); + ITextComponent iTextComponent = null; + Iterator iterator = jsonarray.iterator(); + + while (iterator.hasNext()) { + JsonElement jsonelement1 = (JsonElement) iterator.next(); + ITextComponent iTextComponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); + + if (iTextComponent == null) { + iTextComponent = iTextComponent1; + } else { + iTextComponent.appendSibling(iTextComponent1); + } + } + + return iTextComponent; + } else { + throw new JsonParseException("Don\'t know how to turn " + jsonelement + " into a Component"); + } + } + + public Object deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + return this.a(jsonelement, type, jsondeserializationcontext); + } + }).create(); + + DataConverterSignText() {} + + public int getDataVersion() { + return 101; + } + + public NBTTagCompound convert(NBTTagCompound cmp) { + if ("Sign".equals(cmp.getString("id"))) { + this.convert(cmp, "Text1"); + this.convert(cmp, "Text2"); + this.convert(cmp, "Text3"); + this.convert(cmp, "Text4"); + } + + return cmp; + } + + private void convert(NBTTagCompound nbttagcompound, String s) { + String s1 = nbttagcompound.getString(s); + Object object = null; + + if (!"null".equals(s1) && !StringUtils.isNullOrEmpty(s1)) { + if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { + object = new TextComponentString(s1); + } else { + try { + object = JsonUtils.fromJson(DataConverterSignText.a, s1, ITextComponent.class, true); + if (object == null) { + object = new TextComponentString(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = ITextComponent.Serializer.fromJson(s1); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = ITextComponent.Serializer.fromJsonLenient(s1); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = new TextComponentString(s1); + } + } + } else { + object = new TextComponentString(""); + } + + nbttagcompound.putString(s, ITextComponent.Serializer.toJson((ITextComponent) object)); + } + } + + private static class DataInspectorPlayerVehicle implements DataInspector { + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + if (cmp.contains("RootVehicle", 10)) { + NBTTagCompound nbttagcompound1 = cmp.getCompound("RootVehicle"); + + if (nbttagcompound1.contains("Entity", 10)) { + convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); + } + } + + return cmp; + } + } + + private static class DataInspectorLevelPlayer implements DataInspector { + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + if (cmp.contains("Player", 10)) { + convertCompound(LegacyType.PLAYER, cmp, "Player", sourceVer, targetVer); + } + + return cmp; + } + } + + private static class DataInspectorStructure implements DataInspector { + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + NBTTagList nbttaglist; + int j; + NBTTagCompound nbttagcompound1; + + if (cmp.contains("entities", 9)) { + nbttaglist = cmp.getList("entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (NBTTagCompound) nbttaglist.get(j); + if (nbttagcompound1.contains("nbt", 10)) { + convertCompound(LegacyType.ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); + } + } + } + + if (cmp.contains("blocks", 9)) { + nbttaglist = cmp.getList("blocks", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (NBTTagCompound) nbttaglist.get(j); + if (nbttagcompound1.contains("nbt", 10)) { + convertCompound(LegacyType.BLOCK_ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); + } + } + } + + return cmp; + } + } + + private static class DataInspectorChunks implements DataInspector { + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + if (cmp.contains("Level", 10)) { + NBTTagCompound nbttagcompound1 = cmp.getCompound("Level"); + NBTTagList nbttaglist; + int j; + + if (nbttagcompound1.contains("Entities", 9)) { + nbttaglist = nbttagcompound1.getList("Entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ENTITY, (NBTTagCompound) nbttaglist.get(j), sourceVer, targetVer)); + } + } + + if (nbttagcompound1.contains("TileEntities", 9)) { + nbttaglist = nbttagcompound1.getList("TileEntities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.BLOCK_ENTITY, (NBTTagCompound) nbttaglist.get(j), sourceVer, targetVer)); + } + } + } + + return cmp; + } + } + + private static class DataInspectorEntityPassengers implements DataInspector { + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + if (cmp.contains("Passengers", 9)) { + NBTTagList nbttaglist = cmp.getList("Passengers", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ENTITY, nbttaglist.getCompound(j), sourceVer, targetVer)); + } + } + + return cmp; + } + } + + private static class DataInspectorPlayer implements DataInspector { + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + convertItems(cmp, "Inventory", sourceVer, targetVer); + convertItems(cmp, "EnderItems", sourceVer, targetVer); + if (cmp.contains("ShoulderEntityLeft", 10)) { + convertCompound(LegacyType.ENTITY, cmp, "ShoulderEntityLeft", sourceVer, targetVer); + } + + if (cmp.contains("ShoulderEntityRight", 10)) { + convertCompound(LegacyType.ENTITY, cmp, "ShoulderEntityRight", sourceVer, targetVer); + } + + return cmp; + } + } + + private static class DataInspectorVillagers implements DataInspector { + ResourceLocation entityVillager = getKey("EntityVillager"); + + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { + NBTTagCompound nbttagcompound1 = cmp.getCompound("Offers"); + + if (nbttagcompound1.contains("Recipes", 9)) { + NBTTagList nbttaglist = nbttagcompound1.getList("Recipes", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + NBTTagCompound nbttagcompound2 = nbttaglist.getCompound(j); + + convertItem(nbttagcompound2, "buy", sourceVer, targetVer); + convertItem(nbttagcompound2, "buyB", sourceVer, targetVer); + convertItem(nbttagcompound2, "sell", sourceVer, targetVer); + nbttaglist.set(j, nbttagcompound2); + } + } + } + + return cmp; + } + } + + private static class DataInspectorMobSpawnerMinecart implements DataInspector { + ResourceLocation entityMinecartMobSpawner = getKey("EntityMinecartMobSpawner"); + ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); + + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + String s = cmp.getString("id"); + if (entityMinecartMobSpawner.equals(new ResourceLocation(s))) { + cmp.putString("id", tileEntityMobSpawner.toString()); + convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); + cmp.putString("id", s); + } + + return cmp; + } + } + + private static class DataInspectorMobSpawnerMobs implements DataInspector { + ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); + + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { + if (cmp.contains("SpawnPotentials", 9)) { + NBTTagList nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + NBTTagCompound nbttagcompound1 = nbttaglist.getCompound(j); + + convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); + } + } + + convertCompound(LegacyType.ENTITY, cmp, "SpawnData", sourceVer, targetVer); + } + + return cmp; + } + } + + private static class DataInspectorCommandBlock implements DataInspector { + ResourceLocation tileEntityCommand = getKey("TileEntityCommand"); + + @Override + public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + if (tileEntityCommand.equals(new ResourceLocation(cmp.getString("id")))) { + cmp.putString("id", "Control"); + convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); + cmp.putString("id", "MinecartCommandBlock"); + } + + return cmp; + } + } +} diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 7f4fa238a..1a3958d55 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; import net.minecraft.command.Commands; @@ -53,11 +54,13 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { private final ForgeWorldEdit mod; private final MinecraftServer server; + private final ForgeDataFixer dataFixer; private boolean hookingEvents = false; ForgePlatform(ForgeWorldEdit mod) { this.mod = mod; this.server = ServerLifecycleHooks.getCurrentServer(); + this.dataFixer = new ForgeDataFixer(getDataVersion()); } boolean isHookingEvents() { @@ -75,6 +78,11 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { return 1631; } + @Override + public DataFixer getDataFixer() { + return dataFixer; + } + @Override public boolean isValidMobType(String type) { return net.minecraftforge.registries.ForgeRegistries.ENTITIES.containsKey(new ResourceLocation(type)); From d0ef56326a2f6d4e59975b34027fe8b0c4348547 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 20 May 2019 16:40:42 -0400 Subject: [PATCH 147/366] Remove oudated and unused html readme. Closes #471. (see comment) --- README.html | 197 ---------------------------------------------------- 1 file changed, 197 deletions(-) delete mode 100644 README.html diff --git a/README.html b/README.html deleted file mode 100644 index 54e4fb40d..000000000 --- a/README.html +++ /dev/null @@ -1,197 +0,0 @@ - - - -${project.name} ${version} - - - - - -

    -

    ${project.name} ${version}

    -
    -
    -

    Common Issues

    - -

    I or others don't have permission to build.

    -

    - This is not a problem caused by ${project.name}. - ${project.name} doesn't deny build permissions as it is merely - a world editing program. -

    - -

    ${project.name} doesn't seem to work.

    -

    - A common mistake is making - a syntax error in one of ${project.name}'s configuration files (this is very - fatal unfortunately, and can be caused by a single character typed in the wrong place). Try - asking in IRC - to see whether anyone can help you. -

    - -

    Can I use this with mod blocks?

    -

    - Yes, depending on what you are using WorldEdit with - (Bukkit, Single Player Commands, MinecraftEdu, etc.). We don't guarantee - 100% compatibility with all known custom blocks, - but we have pretty - decent support. Please be aware that support for these mods is - considered 'experimental,' and will likely be for the far forseeable - future. -

    - -

    How do I protect my spawn?

    -

    - You'll have to install our accompanying WorldGuard plugin, which works - in conjunction with ${project.name} in order to protect areas. With it, - you can make a selection with WorldEdit and then 'define' a region - that prevents other from building in it. -

    - -

    Can I use ${project.name}'s selections in my Bukkit plugin?

    -

    - Absolutely! We haven't documented how to yet, but you can try - looking at the Javadocs - for the plugin's main class. You'll have to get a reference to WorldEdit - from Bukkit's plugin manager (don't try to create WorldEditPlugin), and then - call one of its selection methods. -

    - -

    - Still need help? - See the ways that you can get assistance. -

    -
    -
    -

    Contributing

    -

    - Did you know that ${project.name} is open source? That means that you can - read the code and learn from it, as well as modify it and submit back - changes to help the community! -

    - -
    -
    - - \ No newline at end of file From 7b47d9a9457a8a7a1292c502bbed0e266497cb50 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 23 May 2019 21:12:31 -0400 Subject: [PATCH 148/366] Add /tracemask. (#474) Allows setting a mask used for block traces. This allows brush tools to pass through various materials, such as water (e.g. `/tracemask #solid` or `/tracemask !air,water`) before starting to build. By default, a null mask is equivalent to #existing (original behavior). https://gfycat.com/ImmaculateFrayedCockatiel --- .../worldedit/bukkit/WorldEditListener.java | 17 +----- .../worldedit/command/ToolUtilCommands.java | 21 ++++++- .../worldedit/command/tool/BrushTool.java | 23 +++++++- .../worldedit/command/tool/DistanceWand.java | 9 +-- .../command/tool/LongRangeBuildTool.java | 11 +++- .../com/sk89q/worldedit/entity/Player.java | 22 +++++++ .../platform/AbstractPlayerActor.java | 22 ++++++- .../session/request/RequestExtent.java | 3 +- .../com/sk89q/worldedit/util/TargetBlock.java | 59 ++++++++++++++++--- 9 files changed, 150 insertions(+), 37 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java index 15361fc10..69c803880 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.bukkit; -import com.sk89q.util.StringUtil; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; @@ -33,7 +32,6 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerCommandSendEvent; import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -55,12 +53,6 @@ public class WorldEditListener implements Listener { private WorldEditPlugin plugin; - /** - * Called when a player plays an animation, such as an arm swing - * - * @param event Relevant event details - */ - /** * Construct the object; * @@ -112,12 +104,8 @@ public class WorldEditListener implements Listener { return; } - try { - if (event.getHand() == EquipmentSlot.OFF_HAND) { - return; // TODO api needs to be able to get either hand depending on event - // for now just ignore all off hand interacts - } - } catch (NoSuchMethodError | NoSuchFieldError ignored) { + if (event.getHand() == EquipmentSlot.OFF_HAND) { + return; } final Player player = plugin.wrapPlayer(event.getPlayer()); @@ -143,7 +131,6 @@ public class WorldEditListener implements Listener { event.setCancelled(true); } - } else if (action == Action.RIGHT_CLICK_BLOCK) { final Block clickedBlock = event.getClickedBlock(); final Location pos = new Location(world, clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java index e053eccb8..2597372d5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java @@ -51,7 +51,7 @@ public class ToolUtilCommands { @CommandPermissions("worldedit.superpickaxe") public void togglePickaxe(Player player, LocalSession session, @Arg(desc = "The new super pickaxe state", def = "") - Boolean superPickaxe) throws WorldEditException { + Boolean superPickaxe) { boolean hasSuperPickAxe = session.hasSuperPickAxe(); if (superPickaxe != null && superPickaxe == hasSuperPickAxe) { player.printError("Super pickaxe already " + (superPickaxe ? "enabled" : "disabled") + "."); @@ -75,11 +75,10 @@ public class ToolUtilCommands { public void mask(Player player, LocalSession session, @Arg(desc = "The mask to set", def = "") Mask mask) throws WorldEditException { + session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setMask(mask); if (mask == null) { - session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setMask(null); player.print("Brush mask disabled."); } else { - session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setMask(mask); player.print("Brush mask set."); } } @@ -122,4 +121,20 @@ public class ToolUtilCommands { session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setSize(size); player.print("Brush size set."); } + + @Command( + name = "tracemask", + desc = "Set the mask used to stop tool traces" + ) + @CommandPermissions("worldedit.brush.options.tracemask") + public void traceMask(Player player, LocalSession session, + @Arg(desc = "The trace mask to set", def = "") + Mask mask) throws WorldEditException { + session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setTraceMask(mask); + if (mask == null) { + player.print("Trace mask disabled."); + } else { + player.print("Trace mask set."); + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java index cb98b9a3a..2e324f9ee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java @@ -34,7 +34,6 @@ import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.MaskIntersection; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; @@ -47,6 +46,7 @@ public class BrushTool implements TraceTool { protected static int MAX_RANGE = 500; protected int range = -1; private Mask mask = null; + private Mask traceMask = null; private Brush brush = new SphereBrush(); @Nullable private Pattern material; @@ -86,6 +86,24 @@ public class BrushTool implements TraceTool { this.mask = filter; } + /** + * Get the mask used for identifying where to stop traces. + * + * @return the mask used to stop block traces + */ + public @Nullable Mask getTraceMask() { + return mask; + } + + /** + * Set the block mask used for identifying where to stop traces. + * + * @param traceMask the mask used to stop block traces + */ + public void setTraceMask(@Nullable Mask traceMask) { + this.traceMask = traceMask; + } + /** * Set the brush. * @@ -162,8 +180,7 @@ public class BrushTool implements TraceTool { @Override public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { - Location target = null; - target = player.getBlockTrace(getRange(), true); + Location target = player.getBlockTrace(getRange(), true, traceMask); if (target == null) { player.printError("No block in sight!"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java index 5fa95d04b..48d3dbf7a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.util.Location; @@ -58,7 +59,6 @@ public class DistanceWand extends BrushTool implements DoubleActionTraceTool { } return false; - } @Override @@ -78,12 +78,13 @@ public class DistanceWand extends BrushTool implements DoubleActionTraceTool { return false; } - public Location getTarget(Player player) { + private Location getTarget(Player player) { Location target; + Mask mask = getTraceMask(); if (this.range > -1) { - target = player.getBlockTrace(getRange(), true); + target = player.getBlockTrace(getRange(), true, mask); } else { - target = player.getBlockTrace(MAX_RANGE); + target = player.getBlockTrace(MAX_RANGE, false, mask); } if (target == null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java index 155beb4e8..27011c5ea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Location; @@ -91,8 +92,14 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo return false; } - public Location getTargetFace(Player player) { - Location target = player.getBlockTraceFace(getRange(), true); + private Location getTargetFace(Player player) { + Location target; + Mask mask = getTraceMask(); + if (this.range > -1) { + target = player.getBlockTrace(getRange(), true, mask); + } else { + target = player.getBlockTrace(MAX_RANGE, false, mask); + } if (target == null) { player.printError("No block in sight!"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java index d5be2e40d..3673d8842 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Direction; @@ -210,6 +211,17 @@ public interface Player extends Entity, Actor { */ Location getBlockTrace(int range, boolean useLastBlock); + /** + * Get the point of the block being looked at. May return null. + * Will return the farthest away block before matching the stop mask if useLastBlock is true and no other block is found. + * + * @param range how far to checks for blocks + * @param useLastBlock try to return the last valid block not matching the stop mask found + * @param stopMask the mask used to determine when to stop tracing + * @return point + */ + Location getBlockTrace(int range, boolean useLastBlock, @Nullable Mask stopMask); + /** * Get the face that the player is looking at. * @@ -219,6 +231,16 @@ public interface Player extends Entity, Actor { */ Location getBlockTraceFace(int range, boolean useLastBlock); + /** + * Get the face that the player is looking at. + * + * @param range the range + * @param useLastBlock try to return the last valid block not matching the stop mask found + * @param stopMask the mask used to determine when to stop tracing + * @return a face + */ + Location getBlockTraceFace(int range, boolean useLastBlock, @Nullable Mask stopMask); + /** * Get the point of the block being looked at. May return null. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index e7aeac997..f51f992ac 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.NotABlockException; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -41,6 +42,7 @@ import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; +import javax.annotation.Nullable; import java.io.File; /** @@ -323,13 +325,29 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public Location getBlockTrace(int range, boolean useLastBlock) { - TargetBlock tb = new TargetBlock(this, range, 0.2); - return (useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock()); + return getBlockTrace(range, useLastBlock, null); } @Override public Location getBlockTraceFace(int range, boolean useLastBlock) { + return getBlockTraceFace(range, useLastBlock, null); + } + + @Override + public Location getBlockTrace(int range, boolean useLastBlock, @Nullable Mask stopMask) { TargetBlock tb = new TargetBlock(this, range, 0.2); + if (stopMask != null) { + tb.setStopMask(stopMask); + } + return (useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock()); + } + + @Override + public Location getBlockTraceFace(int range, boolean useLastBlock, @Nullable Mask stopMask) { + TargetBlock tb = new TargetBlock(this, range, 0.2); + if (stopMask != null) { + tb.setStopMask(stopMask); + } return (useLastBlock ? tb.getAnyTargetBlockFace() : tb.getTargetBlockFace()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java index dc5aac815..ab47f7c51 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/request/RequestExtent.java @@ -45,7 +45,8 @@ public class RequestExtent implements Extent { if (request == null || !request.isValid()) { request = Request.request(); } - return request.getEditSession(); + final EditSession editSession = request.getEditSession(); + return editSession == null ? request.getWorld() : editSession; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java index 9d0cf2baa..b887168c5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/TargetBlock.java @@ -20,10 +20,15 @@ package com.sk89q.worldedit.util; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.world.World; +import javax.annotation.Nullable; + /** * This class uses an inefficient method to figure out what block a player * is looking towards. @@ -33,7 +38,8 @@ import com.sk89q.worldedit.world.World; */ public class TargetBlock { - private World world; + private final World world; + private int maxDistance; private double checkDistance, curDistance; private BlockVector3 targetPos = BlockVector3.ZERO; @@ -41,6 +47,11 @@ public class TargetBlock { private BlockVector3 prevPos = BlockVector3.ZERO; private Vector3 offset = Vector3.ZERO; + // the mask which dictates when to stop a trace - defaults to stopping at non-air blocks + private Mask stopMask; + // the mask which dictates when to stop a solid block trace - default to BlockMaterial#isMovementBlocker + private Mask solidMask; + /** * Constructor requiring a player, uses default values * @@ -50,6 +61,8 @@ public class TargetBlock { this.world = player.getWorld(); this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(), 300, 1.65, 0.2); + this.stopMask = new ExistingBlockMask(world); + this.solidMask = new SolidBlockMask(world); } /** @@ -62,6 +75,36 @@ public class TargetBlock { public TargetBlock(Player player, int maxDistance, double checkDistance) { this.world = player.getWorld(); this.setValues(player.getLocation().toVector(), player.getLocation().getYaw(), player.getLocation().getPitch(), maxDistance, 1.65, checkDistance); + this.stopMask = new ExistingBlockMask(world); + this.solidMask = new SolidBlockMask(world); + } + + /** + * Set the mask used for determine where to stop traces. + * Setting to null will restore the default. + * + * @param stopMask the mask used to stop traces + */ + public void setStopMask(@Nullable Mask stopMask) { + if (stopMask == null) { + this.stopMask = new ExistingBlockMask(world); + } else { + this.stopMask = stopMask; + } + } + + /** + * Set the mask used for determine where to stop solid block traces. + * Setting to null will restore the default. + * + * @param solidMask the mask used to stop solid block traces + */ + public void setSolidMask(@Nullable Mask solidMask) { + if (solidMask == null) { + this.solidMask = new SolidBlockMask(world); + } else { + this.solidMask = solidMask; + } } /** @@ -79,7 +122,7 @@ public class TargetBlock { this.checkDistance = checkDistance; this.curDistance = 0; xRotation = (xRotation + 90) % 360; - yRotation = yRotation * -1; + yRotation *= -1; double h = (checkDistance * Math.cos(Math.toRadians(yRotation))); @@ -102,15 +145,15 @@ public class TargetBlock { boolean searchForLastBlock = true; Location lastBlock = null; while (getNextBlock() != null) { - if (world.getBlock(targetPos).getBlockType().getMaterial().isAir()) { + if (stopMask.test(targetPos)) { + break; + } else { if (searchForLastBlock) { lastBlock = getCurrentBlock(); if (lastBlock.getBlockY() <= 0 || lastBlock.getBlockY() >= world.getMaxY()) { searchForLastBlock = false; } } - } else { - break; } } Location currentBlock = getCurrentBlock(); @@ -124,7 +167,8 @@ public class TargetBlock { * @return Block */ public Location getTargetBlock() { - while (getNextBlock() != null && world.getBlock(targetPos).getBlockType().getMaterial().isAir()) ; + //noinspection StatementWithEmptyBody + while (getNextBlock() != null && !stopMask.test(targetPos)) ; return getCurrentBlock(); } @@ -135,7 +179,8 @@ public class TargetBlock { * @return Block */ public Location getSolidTargetBlock() { - while (getNextBlock() != null && !world.getBlock(targetPos).getBlockType().getMaterial().isMovementBlocker()) ; + //noinspection StatementWithEmptyBody + while (getNextBlock() != null && !solidMask.test(targetPos)) ; return getCurrentBlock(); } From a3ffb91917fac74219622bedc6bbb97b344b8219 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 18 May 2019 16:47:08 +1000 Subject: [PATCH 149/366] Added suggestions to a lot of factory-related commands --- .../worldedit/command/argument/FactoryConverter.java | 8 ++++++++ .../extension/factory/parser/DefaultBlockParser.java | 7 +++++++ .../extension/factory/parser/DefaultItemParser.java | 9 +++++++++ .../extension/factory/parser/mask/BiomeMaskParser.java | 6 ++++++ .../factory/parser/mask/BlockCategoryMaskParser.java | 6 ++++++ .../extension/factory/parser/mask/BlocksMaskParser.java | 7 +++++++ .../factory/parser/mask/ExpressionMaskParser.java | 4 ++-- .../parser/pattern/BlockCategoryPatternParser.java | 7 +++---- .../factory/parser/pattern/ClipboardPatternParser.java | 7 +++---- .../factory/parser/pattern/SingleBlockPatternParser.java | 8 ++++++++ .../sk89q/worldedit/function/pattern/ExtentPattern.java | 2 +- .../worldedit/internal/registry/AbstractFactory.java | 7 +++++++ .../sk89q/worldedit/internal/registry/InputParser.java | 9 +++++---- .../worldedit/internal/registry/SimpleInputParser.java | 5 +++-- 14 files changed, 75 insertions(+), 17 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index b3b2b8108..826e3a1cd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.command.argument; +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; @@ -41,6 +43,7 @@ import org.enginehub.piston.converter.SuccessfulConversion; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; +import java.util.List; import java.util.function.Function; public class FactoryConverter implements ArgumentConverter { @@ -92,6 +95,11 @@ public class FactoryConverter implements ArgumentConverter { } } + @Override + public List getSuggestions(String input) { + return limitByPrefix(factoryExtractor.apply(worldEdit).getSuggestions(), input); + } + @Override public Component describeAcceptableArguments() { return TextComponent.of("any " + description); 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 d2212a40e..5a962a9a3 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 @@ -52,6 +52,7 @@ import com.sk89q.worldedit.world.registry.LegacyMapper; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.stream.Stream; /** * Parses block input strings. @@ -199,6 +200,12 @@ public class DefaultBlockParser extends InputParser { return blockStates; } + @Override + public Stream getSuggestions() { + // TODO Include states + return BlockType.REGISTRY.keySet().stream(); + } + private BaseBlock parseLogic(String input, ParserContext context) throws InputParseException { BlockType blockType = null; Map, Object> blockStates = new HashMap<>(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java index 13c382cac..52658327e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java @@ -28,7 +28,11 @@ import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class DefaultItemParser extends InputParser { @@ -36,6 +40,11 @@ public class DefaultItemParser extends InputParser { super(worldEdit); } + @Override + public Stream getSuggestions() { + return ItemType.REGISTRY.keySet().stream(); + } + @Override public BaseItem parseFromInput(String input, ParserContext context) throws InputParseException { BaseItem item = null; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java index 11b8bb54c..af887e432 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java @@ -36,6 +36,7 @@ import com.sk89q.worldedit.world.registry.BiomeRegistry; import java.util.Collection; import java.util.HashSet; import java.util.Set; +import java.util.stream.Stream; public class BiomeMaskParser extends InputParser { @@ -43,6 +44,11 @@ public class BiomeMaskParser extends InputParser { super(worldEdit); } + @Override + public Stream getSuggestions() { + return BiomeType.REGISTRY.keySet().stream().map(biomeType -> "$" + biomeType); + } + @Override public Mask parseFromInput(String input, ParserContext context) throws InputParseException { if (!input.startsWith("$")) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java index 8745e60ca..7c20d9ee2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java @@ -29,6 +29,7 @@ import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.world.block.BlockCategory; import java.util.Locale; +import java.util.stream.Stream; public class BlockCategoryMaskParser extends InputParser { @@ -36,6 +37,11 @@ public class BlockCategoryMaskParser extends InputParser { super(worldEdit); } + @Override + public Stream getSuggestions() { + return BlockCategory.REGISTRY.keySet().stream().map(str -> "##" + str); + } + @Override public Mask parseFromInput(String input, ParserContext context) throws InputParseException { if (!input.startsWith("##")) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java index e67a7e8b1..85c414383 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java @@ -28,8 +28,10 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockCategory; import java.util.Set; +import java.util.stream.Stream; /** * Parses mask input strings. @@ -40,6 +42,11 @@ public class BlocksMaskParser extends InputParser { super(worldEdit); } + @Override + public Stream getSuggestions() { + return worldEdit.getBlockFactory().getSuggestions(); + } + @Override public Mask parseFromInput(String component, ParserContext context) throws InputParseException { ParserContext tempContext = new ParserContext(context); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java index 4e254109c..3087610be 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java @@ -52,8 +52,8 @@ public class ExpressionMaskParser extends InputParser { WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment( new RequestExtent(), Vector3.ONE, Vector3.ZERO); exp.setEnvironment(env); - if (context.getActor() instanceof SessionOwner) { - SessionOwner owner = (SessionOwner) context.getActor(); + if (context.getActor() != null) { + SessionOwner owner = context.getActor(); IntSupplier timeout = () -> WorldEdit.getInstance().getSessionManager().get(owner).getTimeout(); return new ExpressionMask(exp, timeout); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java index 769394146..6c83b569f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java @@ -29,10 +29,9 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.world.block.BlockCategory; import com.sk89q.worldedit.world.block.BlockType; -import java.util.List; import java.util.Locale; import java.util.Set; -import java.util.stream.Collectors; +import java.util.stream.Stream; public class BlockCategoryPatternParser extends InputParser { @@ -41,8 +40,8 @@ public class BlockCategoryPatternParser extends InputParser { } @Override - public List getSuggestions() { - return BlockCategory.REGISTRY.keySet().stream().map(str -> "##" + str).collect(Collectors.toList()); + public Stream getSuggestions() { + return BlockCategory.REGISTRY.keySet().stream().map(str -> "##" + str); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java index f0939ed60..1f88aecbd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.extension.factory.parser.pattern; -import com.google.common.collect.Lists; import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -32,7 +31,7 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.session.ClipboardHolder; -import java.util.List; +import java.util.stream.Stream; public class ClipboardPatternParser extends InputParser { @@ -41,8 +40,8 @@ public class ClipboardPatternParser extends InputParser { } @Override - public List getSuggestions() { - return Lists.newArrayList("#clipboard", "#copy"); + public Stream getSuggestions() { + return Stream.of("#clipboard", "#copy"); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java index e71530a2e..8e2b99bae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java @@ -25,6 +25,9 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.stream.Stream; public class SingleBlockPatternParser extends InputParser { @@ -32,6 +35,11 @@ public class SingleBlockPatternParser extends InputParser { super(worldEdit); } + @Override + public Stream getSuggestions() { + return worldEdit.getBlockFactory().getSuggestions(); + } + @Override public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { return new BlockPattern(worldEdit.getBlockFactory().parseFromInput(input, context)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentPattern.java index c0dec41ee..94ab5ea77 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/ExtentPattern.java @@ -28,5 +28,5 @@ public interface ExtentPattern extends Pattern { * * @return the extent for this pattern */ - public Extent getExtent(); + Extent getExtent(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index fcee6abcc..6fd8523c0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -27,8 +27,11 @@ import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * An abstract implementation of a factory for internal usage. @@ -76,6 +79,10 @@ public abstract class AbstractFactory { throw new NoMatchException("No match for '" + input + "'"); } + public Stream getSuggestions() { + return parsers.stream().flatMap(InputParser::getSuggestions); + } + /** * Registers an InputParser to this factory * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java index 575bb9550..a5dc1e992 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.extension.input.ParserContext; import java.util.Collections; import java.util.List; +import java.util.stream.Stream; /** * Input parser interface for {@link AbstractFactory}. @@ -43,11 +44,11 @@ public abstract class InputParser { public abstract E parseFromInput(String input, ParserContext context) throws InputParseException; /** - * Gets a list of suggestions of input to this parser. + * Gets a stream of suggestions of input to this parser. * - * @return a list of suggestions + * @return a stream of suggestions */ - public List getSuggestions() { - return Collections.emptyList(); + public Stream getSuggestions() { + return Stream.empty(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java index d0647f9cc..8ed5f338c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import java.util.List; +import java.util.stream.Stream; /** * An input parser that only performs a single function from aliases. @@ -65,7 +66,7 @@ public abstract class SimpleInputParser extends InputParser { } @Override - public List getSuggestions() { - return Lists.newArrayList(getPrimaryMatcher()); + public Stream getSuggestions() { + return Stream.of(getPrimaryMatcher()); } } From 4804fe64e36d02a103a1f39d3f7fbd93c4938e5b Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sun, 19 May 2019 13:49:37 +1000 Subject: [PATCH 150/366] Don't use a no-op suggester --- .../sk89q/worldedit/command/argument/FactoryConverter.java | 2 +- .../extension/factory/parser/DefaultBlockParser.java | 2 +- .../extension/factory/parser/DefaultItemParser.java | 2 +- .../extension/factory/parser/mask/BiomeMaskParser.java | 2 +- .../factory/parser/mask/BlockCategoryMaskParser.java | 2 +- .../extension/factory/parser/mask/BlocksMaskParser.java | 4 ++-- .../factory/parser/pattern/BlockCategoryPatternParser.java | 2 +- .../factory/parser/pattern/ClipboardPatternParser.java | 2 +- .../factory/parser/pattern/SingleBlockPatternParser.java | 4 ++-- .../sk89q/worldedit/internal/registry/AbstractFactory.java | 5 +++-- .../com/sk89q/worldedit/internal/registry/InputParser.java | 2 +- .../sk89q/worldedit/internal/registry/SimpleInputParser.java | 2 +- 12 files changed, 16 insertions(+), 15 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index 826e3a1cd..d28f15ec9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -97,7 +97,7 @@ public class FactoryConverter implements ArgumentConverter { @Override public List getSuggestions(String input) { - return limitByPrefix(factoryExtractor.apply(worldEdit).getSuggestions(), input); + return factoryExtractor.apply(worldEdit).getSuggestions(input); } @Override 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 5a962a9a3..a2d069bd8 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 @@ -201,7 +201,7 @@ public class DefaultBlockParser extends InputParser { } @Override - public Stream getSuggestions() { + public Stream getSuggestions(String input) { // TODO Include states return BlockType.REGISTRY.keySet().stream(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java index 52658327e..702e54458 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java @@ -41,7 +41,7 @@ public class DefaultItemParser extends InputParser { } @Override - public Stream getSuggestions() { + public Stream getSuggestions(String input) { return ItemType.REGISTRY.keySet().stream(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java index af887e432..d484b4ff9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java @@ -45,7 +45,7 @@ public class BiomeMaskParser extends InputParser { } @Override - public Stream getSuggestions() { + public Stream getSuggestions(String input) { return BiomeType.REGISTRY.keySet().stream().map(biomeType -> "$" + biomeType); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java index 7c20d9ee2..630386b56 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java @@ -38,7 +38,7 @@ public class BlockCategoryMaskParser extends InputParser { } @Override - public Stream getSuggestions() { + public Stream getSuggestions(String input) { return BlockCategory.REGISTRY.keySet().stream().map(str -> "##" + str); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java index 85c414383..df7ed3a16 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java @@ -43,8 +43,8 @@ public class BlocksMaskParser extends InputParser { } @Override - public Stream getSuggestions() { - return worldEdit.getBlockFactory().getSuggestions(); + public Stream getSuggestions(String input) { + return worldEdit.getBlockFactory().getSuggestions(input).stream(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java index 6c83b569f..f9e0f8052 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java @@ -40,7 +40,7 @@ public class BlockCategoryPatternParser extends InputParser { } @Override - public Stream getSuggestions() { + public Stream getSuggestions(String input) { return BlockCategory.REGISTRY.keySet().stream().map(str -> "##" + str); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java index 1f88aecbd..4029c4359 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java @@ -40,7 +40,7 @@ public class ClipboardPatternParser extends InputParser { } @Override - public Stream getSuggestions() { + public Stream getSuggestions(String input) { return Stream.of("#clipboard", "#copy"); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java index 8e2b99bae..3bd852513 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java @@ -36,8 +36,8 @@ public class SingleBlockPatternParser extends InputParser { } @Override - public Stream getSuggestions() { - return worldEdit.getBlockFactory().getSuggestions(); + public Stream getSuggestions(String input) { + return worldEdit.getBlockFactory().getSuggestions(input).stream(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index 6fd8523c0..d4ec8bef8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.internal.registry; import static com.google.common.base.Preconditions.checkNotNull; +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; @@ -79,8 +80,8 @@ public abstract class AbstractFactory { throw new NoMatchException("No match for '" + input + "'"); } - public Stream getSuggestions() { - return parsers.stream().flatMap(InputParser::getSuggestions); + public List getSuggestions(String input) { + return limitByPrefix(parsers.stream().flatMap(parser -> parser.getSuggestions(input)), input); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java index a5dc1e992..5862d9cf9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java @@ -48,7 +48,7 @@ public abstract class InputParser { * * @return a stream of suggestions */ - public Stream getSuggestions() { + public Stream getSuggestions(String input) { return Stream.empty(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java index 8ed5f338c..013e45958 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java @@ -66,7 +66,7 @@ public abstract class SimpleInputParser extends InputParser { } @Override - public Stream getSuggestions() { + public Stream getSuggestions(String input) { return Stream.of(getPrimaryMatcher()); } } From 4b15439e03f05fdb5454bd2a24000984e519d6e0 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 25 May 2019 00:35:12 -0400 Subject: [PATCH 151/366] Don't attempt to update empty or invalid flower pots. --- .../io/legacycompat/FlowerPotCompatibilityHandler.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 df18a95da..92e998f75 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 @@ -41,6 +41,9 @@ public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { Tag item = values.get("Item"); if (item instanceof StringTag) { String id = ((StringTag) item).getValue(); + if (id.isEmpty()) { + return (B) BlockTypes.FLOWER_POT.getDefaultState(); + } int data = 0; Tag dataTag = values.get("Data"); if (dataTag instanceof IntTag) { @@ -75,7 +78,7 @@ public class FlowerPotCompatibilityHandler implements NBTCompatibilityHandler { break; } String plantedName = null; - if (newId == 0) { + if (newId == 0 && id.startsWith("minecraft:")) { plantedName = id.substring(10); } else { BlockState plantedWithData = LegacyMapper.getInstance().getBlockFromLegacy(newId, data); From 48fb6691197cbf476dceab9dc837815019819762 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 25 May 2019 18:11:23 -0400 Subject: [PATCH 152/366] Guard against reloads breaking too much. --- .../worldedit/bukkit/WorldEditPlugin.java | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) 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 3c147456c..1fb7633bf 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 @@ -87,8 +87,9 @@ import static com.google.common.base.Preconditions.checkNotNull; public class WorldEditPlugin extends JavaPlugin implements TabCompleter { private static final Logger log = LoggerFactory.getLogger(WorldEditPlugin.class); - public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; + static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; private static WorldEditPlugin INSTANCE; + private static WorldInitListener worldInitListener = null; private BukkitImplAdapter bukkitAdapter; private BukkitServerInterface server; @@ -123,13 +124,33 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { getServer().getPluginManager().registerEvents(new WorldEditListener(this), this); // register this so we can load world-dependent data right as the first world is loading - getServer().getPluginManager().registerEvents(new WorldInitListener(), this); + if (worldInitListener != null) { + getLogger().warning("Server reload detected. This may cause various issues with WorldEdit and dependant plugins."); + try { + // these don't stick around between reload + loadAdapter(); + loadConfig(); + } catch (Throwable ignored) { + } + } else { + getServer().getPluginManager().registerEvents((worldInitListener = new WorldInitListener()), this); + } // Enable metrics new Metrics(this); } - public void setupRegistries() { + private void setupWorldData() { + loadAdapter(); // Need an adapter to work with special blocks with NBT data + setupRegistries(); + WorldEdit.getInstance().loadMappings(); + loadConfig(); // Load configuration + setupTags(); + + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + } + + private void setupRegistries() { // Biome for (Biome biome : Biome.values()) { String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT); @@ -434,14 +455,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { public void onWorldInit(@SuppressWarnings("unused") WorldInitEvent event) { if (loaded) return; loaded = true; - - loadAdapter(); // Need an adapter to work with special blocks with NBT data - setupRegistries(); - WorldEdit.getInstance().loadMappings(); - loadConfig(); // Load configuration - setupTags(); - - WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + setupWorldData(); } } } From 3b2b7f2c684df70f01aaf5a8b013ab90ec24cb58 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 26 May 2019 17:00:45 -0700 Subject: [PATCH 153/366] Initial attempt at restoring regen functionality (#475) --- .../com/sk89q/worldedit/forge/ForgeWorld.java | 85 ++++++++++--------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 3aadc12cc..c5b5f8fba 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.forge; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.io.Files; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; @@ -33,6 +34,7 @@ import com.sk89q.worldedit.internal.Constants; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Location; @@ -55,6 +57,7 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumActionResult; import net.minecraft.util.ResourceLocation; @@ -62,6 +65,9 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.chunk.storage.AnvilSaveHandler; +import net.minecraft.world.gen.ChunkProviderServer; import net.minecraft.world.gen.feature.BigBrownMushroomFeature; import net.minecraft.world.gen.feature.BigRedMushroomFeature; import net.minecraft.world.gen.feature.BigTreeFeature; @@ -79,7 +85,9 @@ import net.minecraft.world.gen.feature.SwampTreeFeature; import net.minecraft.world.gen.feature.TallTaigaTreeFeature; import net.minecraft.world.gen.feature.TreeFeature; import net.minecraft.world.storage.WorldInfo; +import net.minecraftforge.common.DimensionManager; +import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -99,7 +107,7 @@ public class ForgeWorld extends AbstractWorld { private static final IBlockState JUNGLE_LOG = Blocks.JUNGLE_LOG.getDefaultState(); private static final IBlockState JUNGLE_LEAF = Blocks.JUNGLE_LEAVES.getDefaultState().with(BlockLeaves.PERSISTENT, Boolean.TRUE); private static final IBlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(BlockLeaves.PERSISTENT, Boolean.TRUE); - + private final WeakReference worldRef; /** @@ -280,46 +288,41 @@ public class ForgeWorld extends AbstractWorld { @Override public boolean regenerate(Region region, EditSession editSession) { - // TODO Fix for 1.13 - return false; -// // Don't even try to regen if it's going to fail. -// IChunkProvider provider = getWorld().getChunkProvider(); -// if (!(provider instanceof ChunkProviderServer)) { -// return false; -// } -// -// File saveFolder = Files.createTempDir(); -// // register this just in case something goes wrong -// // normally it should be deleted at the end of this method -// saveFolder.deleteOnExit(); -// -// WorldServer originalWorld = (WorldServer) getWorld(); -// -// MinecraftServer server = originalWorld.getServer(); -// AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); -// World freshWorld = new WorldServer(server, saveHandler, originalWorld.getSavedDataStorage(), originalWorld.getWorldInfo(), originalWorld.dimension.getType(), originalWorld.profiler).func_212251_i__(); -// -// // Pre-gen all the chunks -// // We need to also pull one more chunk in every direction -// CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16)); -// for (BlockVector2 chunk : expandedPreGen.getChunks()) { -// freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ()); -// } -// -// ForgeWorld from = new ForgeWorld(freshWorld); -// try { -// for (BlockVector3 vec : region) { -// editSession.setBlock(vec, from.getFullBlock(vec)); -// } -// } catch (MaxChangedBlocksException e) { -// throw new RuntimeException(e); -// } finally { -// saveFolder.delete(); -// DimensionManager.setWorld(originalWorld.dimension.getType(), null, server); -// DimensionManager.setWorld(originalWorld.dimension.getType(), originalWorld, server); -// } -// -// return true; + // Don't even try to regen if it's going to fail. + IChunkProvider provider = getWorld().getChunkProvider(); + if (!(provider instanceof ChunkProviderServer)) { + return false; + } + + File saveFolder = Files.createTempDir(); + // register this just in case something goes wrong + // normally it should be deleted at the end of this method + saveFolder.deleteOnExit(); + try { + WorldServer originalWorld = (WorldServer) getWorld(); + + MinecraftServer server = originalWorld.getServer(); + AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); + World freshWorld = new WorldServer(server, saveHandler, originalWorld.getSavedDataStorage(), originalWorld.getWorldInfo(), originalWorld.dimension.getType(), originalWorld.profiler).init(); + + // Pre-gen all the chunks + // We need to also pull one more chunk in every direction + CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16)); + for (BlockVector2 chunk : expandedPreGen.getChunks()) { + freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ()); + } + + ForgeWorld from = new ForgeWorld(freshWorld); + for (BlockVector3 vec : region) { + editSession.setBlock(vec, from.getFullBlock(vec)); + } + } catch (MaxChangedBlocksException e) { + throw new RuntimeException(e); + } finally { + saveFolder.delete(); + } + + return true; } @Nullable From 871c25e1cdd28ef61a1b80b03d59285da12ced12 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 27 May 2019 19:47:56 -0400 Subject: [PATCH 154/366] Initial support for 1.14.2. --- .../src/main/resources/worldedit-adapters.jar | Bin 450923 -> 642635 bytes .../worldedit/command/SchematicCommands.java | 8 +++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index 74ff20abd745b653bdb0c60e4b536fb9b3ad1364..0045effc1a6f4beceef09da3c5406e99ea23f526 100644 GIT binary patch delta 213974 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�Lx2aM?G*E(g52_ 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 W-#LMeIgJyIMimD0nFD-FgZVFvjLZ)J delta 85332 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Μkx$*nG{h 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 Date: Sun, 26 May 2019 02:20:02 -0400 Subject: [PATCH 155/366] Add comprehensive suggestions to many commands. All patterns now have suggestions, including recursive patterns. Suggestions will suggest blocks and block states. All masks now have suggestions, though mask intersections are not yet supported due to issues with quotes strings. EntityRemover and ItemFactory now also have completions, as well as all RegistryConverters (though I am unsure how many are actually used). Also use paper's AsyncTabComplete event, if available. --- config/checkstyle/import-control.xml | 2 +- worldedit-bukkit/build.gradle | 5 +- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 2 +- .../worldedit/bukkit/WorldEditPlugin.java | 39 ++++- .../main/java/com/sk89q/util/StringUtil.java | 9 +- .../worldedit/command/RegionCommands.java | 2 +- .../argument/EntityRemoverConverter.java | 13 ++ .../command/argument/FactoryConverter.java | 2 - .../command/argument/RegistryConverter.java | 6 + .../command/factory/ItemUseFactory.java | 2 +- .../command/util/SuggestionHelper.java | 143 ++++++++++++++++++ .../extension/factory/BlockFactory.java | 2 +- .../extension/factory/MaskFactory.java | 6 +- .../extension/factory/PatternFactory.java | 2 +- .../factory/parser/DefaultBlockParser.java | 40 ++++- .../factory/parser/DefaultItemParser.java | 15 +- .../factory/parser/mask/BiomeMaskParser.java | 18 ++- .../parser/mask/BlockCategoryMaskParser.java | 3 +- .../parser/mask/BlockStateMaskParser.java | 10 ++ .../factory/parser/mask/BlocksMaskParser.java | 1 - .../parser/mask/ExistingMaskParser.java | 6 +- .../parser/mask/ExpressionMaskParser.java | 10 +- .../parser/mask/LazyRegionMaskParser.java | 9 +- .../factory/parser/mask/NegateMaskParser.java | 13 ++ .../factory/parser/mask/NoiseMaskParser.java | 16 +- .../factory/parser/mask/OffsetMaskParser.java | 14 ++ .../factory/parser/mask/RegionMaskParser.java | 6 +- .../factory/parser/mask/SolidMaskParser.java | 6 +- .../pattern/BlockCategoryPatternParser.java | 3 +- .../pattern/ClipboardPatternParser.java | 23 ++- .../parser/pattern/RandomPatternParser.java | 28 +++- .../pattern/RandomStatePatternParser.java | 14 ++ .../pattern/SingleBlockPatternParser.java | 1 - .../TypeOrStateApplyingPatternParser.java | 30 +++- .../internal/registry/AbstractFactory.java | 7 +- .../internal/registry/InputParser.java | 4 +- .../internal/registry/SimpleInputParser.java | 15 +- 37 files changed, 463 insertions(+), 64 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index c783552a9..a291b5ad5 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -44,7 +44,7 @@ - + diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 21b5bdebb..8076e2ca1 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -19,7 +19,8 @@ dependencies { compile project(':worldedit-libs:bukkit') compile 'com.sk89q:dummypermscompat:1.10' compile 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz - compile "io.papermc:paperlib:1.0.1" + compile 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' + compile "io.papermc:paperlib:1.0.2" compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' compile 'org.bstats:bstats-bukkit:1.4' testCompile 'org.mockito:mockito-core:1.9.0-rc1' @@ -53,7 +54,7 @@ shadowJar { include(dependency("org.bstats:bstats-bukkit:1.4")) } relocate ("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") { - include(dependency("io.papermc:paperlib:1.0.1")) + include(dependency("io.papermc:paperlib:1.0.2")) } } } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index d02bd1abc..b8418d03d 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -151,7 +151,7 @@ public class BukkitAdapter { if (match != null) { return match; } else { - throw new IllegalArgumentException("Can't find a Bukkit world for " + world); + throw new IllegalArgumentException("Can't find a Bukkit world for " + world.getName()); } } } 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 1fb7633bf..570ef30be 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 @@ -49,6 +49,7 @@ import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemCategory; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.weather.WeatherTypes; +import io.papermc.lib.PaperLib; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -75,6 +76,7 @@ import java.io.InputStream; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.jar.JarFile; import java.util.logging.Level; import java.util.zip.ZipEntry; @@ -122,6 +124,10 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // Now we can register events getServer().getPluginManager().registerEvents(new WorldEditListener(this), this); + // register async tab complete, if available + if (PaperLib.isPaper()) { + getServer().getPluginManager().registerEvents(new AsyncTabCompleteListener(), this); + } // register this so we can load world-dependent data right as the first world is loading if (worldInitListener != null) { @@ -138,6 +144,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // Enable metrics new Metrics(this); + PaperLib.suggestPaper(this); } private void setupWorldData() { @@ -171,11 +178,12 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { ).toImmutableState(); BlockState defaultState = blockState.getBlockType().getAllStates().get(0); for (Map.Entry, Object> propertyObjectEntry : state.getStates().entrySet()) { - defaultState = defaultState.with((Property) propertyObjectEntry.getKey(), propertyObjectEntry.getValue()); + //noinspection unchecked + defaultState = defaultState.with((Property) propertyObjectEntry.getKey(), propertyObjectEntry.getValue()); } return defaultState; } catch (InputParseException e) { - e.printStackTrace(); + getLogger().log(Level.WARNING, "Error loading block state for " + material.getKey(), e); return blockState; } })); @@ -206,7 +214,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { for (Tag itemTag : Bukkit.getTags(Tag.REGISTRY_ITEMS, Material.class)) { ItemCategory.REGISTRY.register(itemTag.getKey().toString(), new ItemCategory(itemTag.getKey().toString())); } - } catch (NoSuchMethodError e) { + } catch (NoSuchMethodError ignored) { getLogger().warning("The version of Spigot/Paper you are using doesn't support Tags. The usage of tags with WorldEdit will not work until you update."); } } @@ -458,4 +466,29 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { setupWorldData(); } } + + private class AsyncTabCompleteListener implements Listener { + AsyncTabCompleteListener() { + } + + @SuppressWarnings("UnnecessaryFullyQualifiedName") + @EventHandler(ignoreCancelled = true) + public void onAsyncTabComplete(com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event) { + if (!event.isCommand()) return; + + String buffer = event.getBuffer(); + final String[] parts = buffer.split(" "); + if (parts.length < 1) return; + final String label = parts[0]; + final Optional command + = WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().getCommand(label); + if (!command.isPresent()) return; + + CommandSuggestionEvent suggestEvent = new CommandSuggestionEvent(wrapCommandSender(event.getSender()), event.getBuffer()); + getWorldEdit().getEventBus().post(suggestEvent); + + event.setCompletions(CommandUtil.fixSuggestions(event.getBuffer(), suggestEvent.getSuggestions())); + event.setHandled(true); + } + } } 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 80792b846..dd4bf4b29 100644 --- a/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/util/StringUtil.java @@ -306,7 +306,11 @@ public final class StringUtil { } public static List parseListInQuotes(String[] input, char delimiter, char quoteOpen, char quoteClose) { - List parsableBlocks = new ArrayList<>(); + return parseListInQuotes(input, delimiter, quoteOpen, quoteClose, false); + } + + public static List parseListInQuotes(String[] input, char delimiter, char quoteOpen, char quoteClose, boolean appendLeftover) { + List parsableBlocks = new ArrayList<>(); StringBuilder buffer = new StringBuilder(); for (String split : input) { if (split.indexOf(quoteOpen) != -1 && split.indexOf(quoteClose) == -1) { @@ -321,6 +325,9 @@ public final class StringUtil { buffer.append(split).append(delimiter); } } + if (appendLeftover && buffer.length() != 0) { + parsableBlocks.add(buffer.delete(buffer.length() - 1, buffer.length()).toString()); + } return parsableBlocks; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index ec3c09e4a..262cc57f6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -89,7 +89,7 @@ public class RegionCommands { @Logging(REGION) public int set(Player player, EditSession editSession, @Selection Region region, - @Arg(desc = "The patter of blocks to set") + @Arg(desc = "The pattern of blocks to set") Pattern pattern) { RegionFunction set = new BlockReplace(editSession, pattern); RegionVisitor visitor = new RegionVisitor(region, set); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java index d2e4b6e35..cdbc63e53 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EntityRemoverConverter.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.command.argument; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.command.util.EntityRemover; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -30,12 +31,19 @@ import org.enginehub.piston.converter.SuccessfulConversion; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; +import java.util.List; + +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + public class EntityRemoverConverter implements ArgumentConverter { public static void register(CommandManager commandManager) { commandManager.registerConverter(Key.of(EntityRemover.class), new EntityRemoverConverter()); } + private final List suggestions + = ImmutableList.of("projectiles", "items", "paintings", "itemframes", "boats", "minecarts", "tnt", "xp", "all"); + private EntityRemoverConverter() { } @@ -46,6 +54,11 @@ public class EntityRemoverConverter implements ArgumentConverter ); } + @Override + public List getSuggestions(String input) { + return limitByPrefix(suggestions.stream(), input); + } + @Override public ConversionResult convert(String argument, InjectedValueAccess context) { try { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index d28f15ec9..d6259abf3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.command.argument; -import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; - import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java index a37c5b174..264b1af0c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.command.argument; import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; import com.sk89q.worldedit.registry.Registry; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -84,10 +85,12 @@ public final class RegistryConverter implements ArgumentConvert private final Registry registry; private final TextComponent choices; + private final boolean namespaced; private RegistryConverter(Registry registry) { this.registry = registry; this.choices = TextComponent.of("any " + registry.getName()); + this.namespaced = registry instanceof NamespacedRegistry; } @Override @@ -106,6 +109,9 @@ public final class RegistryConverter implements ArgumentConvert @Override public List getSuggestions(String input) { + if (namespaced && input.indexOf(':') < 0) { + input = "minecraft:" + input; + } return limitByPrefix(registry.keySet().stream(), input); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java index 8b25780d4..a099a78a1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java @@ -42,6 +42,6 @@ public final class ItemUseFactory implements Contextual { @Override public String toString() { - return "application of the item " + item.getType() + ":" + item.getNbtData(); + return "application of the item " + item.getType(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java new file mode 100644 index 000000000..acf18f041 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java @@ -0,0 +1,143 @@ +/* + * 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.command.util; + +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class SuggestionHelper { + private SuggestionHelper() { + } + + public static Stream getBlockCategorySuggestions(String tag, boolean allowRandom) { + final Stream allTags = BlockCategory.REGISTRY.keySet().stream().map(str -> "##" + str); + if (tag.isEmpty()) { + return allTags; + } + if (tag.startsWith("#")) { + String key; + if (tag.startsWith("##")) { + key = tag.substring(2); + if (key.isEmpty()) { + return allTags; + } + boolean anyState = false; + if (allowRandom && key.charAt(0) == '*') { + key = key.substring(1); + anyState = true; + } + if (key.indexOf(':') < 0) { + key = "minecraft:" + key; + } + String finalTag = key.toLowerCase(Locale.ROOT); + final Stream stream = BlockCategory.REGISTRY.keySet().stream().filter(s -> + s.startsWith(finalTag)); + return anyState ? stream.map(s -> "##*" + s) : stream.map(s -> "##" + s); + } else if (tag.length() == 1) { + return allTags; + } + } + return Stream.empty(); + } + + public static Stream getBlockPropertySuggestions(String blockType, String props) { + BlockType type = BlockTypes.get(blockType.toLowerCase(Locale.ROOT)); + if (type == null) { + return Stream.empty(); + } + final Map> propertyMap = type.getPropertyMap(); + Set matchedProperties = new HashSet<>(); + String[] propParts = props.split(",", -1); + for (int i = 0; i < propParts.length; i++) { + String[] propVal = propParts[i].split("="); + final String matchProp = propVal[0].toLowerCase(Locale.ROOT); + if (i == propParts.length - 1) { + // suggest for next property + String previous = Arrays.stream(propParts, 0, propParts.length - 1).collect(Collectors.joining(",")) + + (propParts.length == 1 ? "" : ","); + String lastValidInput = (blockType + "[" + previous).toLowerCase(Locale.ROOT); + if (propVal.length == 1) { + // only property, no value yet + final List> matchingProps = propertyMap.entrySet().stream() + .filter(p -> !matchedProperties.contains(p.getKey()) && p.getKey().startsWith(matchProp)) + .map(Map.Entry::getValue).collect(Collectors.toList()); + switch (matchingProps.size()) { + case 0: + return propertyMap.keySet().stream().filter(p -> !matchedProperties.contains(p)).map(prop -> + lastValidInput + prop + "="); + case 1: + return matchingProps.get(0).getValues().stream().map(val -> + lastValidInput + matchingProps.get(0).getName() + "=" + + val.toString().toLowerCase(Locale.ROOT)); + default: + return matchingProps.stream().map(p -> lastValidInput + p.getName() + "="); + } + } else { + Property prop = propertyMap.get(matchProp); + if (prop == null) { + return Stream.empty(); + } + final List values = prop.getValues().stream().map(v -> v.toString().toLowerCase(Locale.ROOT)).collect(Collectors.toList()); + String matchVal = propVal[1].toLowerCase(Locale.ROOT); + List matchingVals = values.stream().filter(val -> val.startsWith(matchVal)).collect(Collectors.toList()); + if (matchingVals.isEmpty()) { + return values.stream().map(val -> lastValidInput + prop.getName() + "=" + val); + } else { + if (matchingVals.size() == 1 && matchingVals.get(0).equals(matchVal)) { + String currProp = lastValidInput + prop.getName() + "=" + matchVal; + if (matchingVals.size() < values.size()) { + return Stream.of(currProp + "] ", currProp + ","); + } + return Stream.of(currProp + "] "); + } + return matchingVals.stream().map(val -> lastValidInput + prop.getName() + "=" + val); + } + } + } else { + // validate previous properties + if (propVal.length != 2) { + return Stream.empty(); + } + Property prop = propertyMap.get(matchProp); + if (prop == null) { + return Stream.empty(); + } + try { + prop.getValueFor(propVal[1]); + matchedProperties.add(prop.getName()); + } catch (IllegalArgumentException ignored) { + return Stream.empty(); + } + } + } + return Stream.empty(); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java index 235f0ae3e..c00583183 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java @@ -61,7 +61,7 @@ public class BlockFactory extends AbstractFactory { public Set parseFromListInput(String input, ParserContext context) throws InputParseException { Set blocks = new HashSet<>(); String[] splits = input.split(","); - for (String token : StringUtil.parseListInQuotes(splits, ',', '[', ']')) { + for (String token : StringUtil.parseListInQuotes(splits, ',', '[', ']', true)) { blocks.add(parseFromInput(token, context)); } return blocks; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java index 29bb9eb25..31b1ac2df 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java @@ -64,13 +64,15 @@ public final class MaskFactory extends AbstractFactory { register(new SolidMaskParser(worldEdit)); register(new LazyRegionMaskParser(worldEdit)); register(new RegionMaskParser(worldEdit)); - register(new BlockCategoryMaskParser(worldEdit)); register(new OffsetMaskParser(worldEdit)); - register(new BiomeMaskParser(worldEdit)); register(new NoiseMaskParser(worldEdit)); register(new BlockStateMaskParser(worldEdit)); register(new NegateMaskParser(worldEdit)); register(new ExpressionMaskParser(worldEdit)); + + register(new BlockCategoryMaskParser(worldEdit)); + register(new BiomeMaskParser(worldEdit)); + register(new BlocksMaskParser(worldEdit)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java index 8457f3fc3..0df1dc40c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java @@ -50,10 +50,10 @@ public final class PatternFactory extends AbstractFactory { register(new RandomPatternParser(worldEdit)); // individual patterns - register(new BlockCategoryPatternParser(worldEdit)); register(new ClipboardPatternParser(worldEdit)); register(new TypeOrStateApplyingPatternParser(worldEdit)); register(new RandomStatePatternParser(worldEdit)); + register(new BlockCategoryPatternParser(worldEdit)); // inner-most pattern: just one block - must be last register(new SingleBlockPatternParser(worldEdit)); 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 a2d069bd8..4a03a5471 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 @@ -27,6 +27,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.MobSpawnerBlock; import com.sk89q.worldedit.blocks.SignBlock; import com.sk89q.worldedit.blocks.SkullBlock; +import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.input.InputParseException; @@ -38,7 +39,6 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.HandSide; -import com.sk89q.worldedit.util.formatting.component.ErrorFormat; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -101,7 +101,7 @@ public class DefaultBlockParser extends InputParser { } } - private static String[] EMPTY_STRING_ARRAY = new String[]{}; + private static String[] EMPTY_STRING_ARRAY = {}; /** * Backwards compatibility for wool colours in block syntax. @@ -169,11 +169,9 @@ public class DefaultBlockParser extends InputParser { Property propertyKey = (Property) type.getPropertyMap().get(parts[0]); if (propertyKey == null) { if (context.getActor() != null) { - context.getActor().print(ErrorFormat.wrap("Unknown property ", parts[0], " for block ", type.getName(), - ". Defaulting to base.")); + throw new NoMatchException("Unknown property " + parts[0] + " for block " + type.getName()); } else { WorldEdit.logger.warn("Unknown property " + parts[0] + " for block " + type.getName()); -// throw new NoMatchException("Unknown property " + parts[0] + " for block " + type.getName()); } return Maps.newHashMap(); } @@ -202,8 +200,29 @@ public class DefaultBlockParser extends InputParser { @Override public Stream getSuggestions(String input) { - // TODO Include states - return BlockType.REGISTRY.keySet().stream(); + final int idx = input.lastIndexOf('['); + if (idx < 0) { + if (input.indexOf(':') == -1) { + String key = ("minecraft:" + input).toLowerCase(Locale.ROOT); + return BlockType.REGISTRY.keySet().stream().filter(s -> s.startsWith(key)); + } + if (input.contains(",")) { + return Stream.empty(); + } + return BlockType.REGISTRY.keySet().stream(); + } + String blockType = input.substring(0, idx); + BlockType type = BlockTypes.get(blockType.toLowerCase(Locale.ROOT)); + if (type == null) { + return Stream.empty(); + } + + String props = input.substring(idx + 1); + if (props.isEmpty()) { + return type.getProperties().stream().map(p -> input + p.getName() + "="); + } + + return SuggestionHelper.getBlockPropertySuggestions(blockType, props); } private BaseBlock parseLogic(String input, ParserContext context) throws InputParseException { @@ -238,6 +257,13 @@ public class DefaultBlockParser extends InputParser { typeString = blockAndExtraData[0]; } else { typeString = blockAndExtraData[0].substring(0, stateStart); + if (stateStart + 1 >= blockAndExtraData[0].length()) { + throw new InputParseException("Invalid format. Hanging bracket @ " + stateStart + "."); + } + int stateEnd = blockAndExtraData[0].lastIndexOf(']'); + if (stateEnd < 0) { + throw new InputParseException("Invalid format. Unclosed property."); + } stateString = blockAndExtraData[0].substring(stateStart + 1, blockAndExtraData[0].length() - 1); } if (typeString.isEmpty()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java index 702e54458..e325b24a1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java @@ -28,10 +28,7 @@ import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; -import java.util.ArrayList; -import java.util.List; import java.util.Locale; -import java.util.stream.Collectors; import java.util.stream.Stream; public class DefaultItemParser extends InputParser { @@ -42,7 +39,11 @@ public class DefaultItemParser extends InputParser { @Override public Stream getSuggestions(String input) { - return ItemType.REGISTRY.keySet().stream(); + if (input.indexOf(':') == -1) { + input = "minecraft:" + input; + } + String key = input; + return ItemType.REGISTRY.keySet().stream().filter(s -> s.startsWith(key)); } @Override @@ -58,8 +59,10 @@ public class DefaultItemParser extends InputParser { } else { type = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(split[0]), Integer.parseInt(split[1])); } - item = new BaseItem(type); - } catch (NumberFormatException e) { + if (type != null) { + item = new BaseItem(type); + } + } catch (NumberFormatException ignored) { } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java index d484b4ff9..db0ab21e7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java @@ -35,6 +35,7 @@ import com.sk89q.worldedit.world.registry.BiomeRegistry; import java.util.Collection; import java.util.HashSet; +import java.util.Locale; import java.util.Set; import java.util.stream.Stream; @@ -46,7 +47,22 @@ public class BiomeMaskParser extends InputParser { @Override public Stream getSuggestions(String input) { - return BiomeType.REGISTRY.keySet().stream().map(biomeType -> "$" + biomeType); + final Stream allBiomes = BiomeType.REGISTRY.keySet().stream().map(biomeType -> "$" + biomeType); + if (input.isEmpty()) { + return allBiomes; + } + if (input.charAt(0) == '$') { + String key = input.substring(1); + if (key.isEmpty()) { + return allBiomes; + } + if (key.indexOf(':') < 0) { + key = "minecraft:" + key; + } + String biomeId = key.toLowerCase(Locale.ROOT); + return BiomeType.REGISTRY.keySet().stream().filter(s -> s.startsWith(biomeId)).map(s -> "$" + s); + } + return Stream.empty(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java index 630386b56..ee7bebf44 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extension.factory.parser.mask; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.BlockCategoryMask; @@ -39,7 +40,7 @@ public class BlockCategoryMaskParser extends InputParser { @Override public Stream getSuggestions(String input) { - return BlockCategory.REGISTRY.keySet().stream().map(str -> "##" + str); + return SuggestionHelper.getBlockCategorySuggestions(input, false); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java index 0a2bd6e56..95884b821 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java @@ -28,12 +28,22 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.session.request.RequestExtent; +import java.util.stream.Stream; + public class BlockStateMaskParser extends InputParser { public BlockStateMaskParser(WorldEdit worldEdit) { super(worldEdit); } + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("^[", "^=["); + } + return Stream.of("^[", "^=[").filter(s -> s.startsWith(input)); // no block type, can't suggest states + } + @Override public Mask parseFromInput(String input, ParserContext context) throws InputParseException { if (!(input.startsWith("^[") || input.startsWith("^=[")) || !input.endsWith("]")) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java index df7ed3a16..8580eb8a1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java @@ -28,7 +28,6 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockCategory; import java.util.Set; import java.util.stream.Stream; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java index 5249d47ad..21feb6449 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.extension.factory.parser.mask; -import com.google.common.collect.Lists; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.ExistingBlockMask; @@ -31,13 +31,15 @@ import java.util.List; public class ExistingMaskParser extends SimpleInputParser { + private final List aliases = ImmutableList.of("#existing"); + public ExistingMaskParser(WorldEdit worldEdit) { super(worldEdit); } @Override public List getMatchedAliases() { - return Lists.newArrayList("#existing"); + return aliases; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java index 3087610be..ac104e198 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java @@ -30,10 +30,10 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.session.SessionOwner; -import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.session.request.RequestExtent; import java.util.function.IntSupplier; +import java.util.stream.Stream; public class ExpressionMaskParser extends InputParser { @@ -41,6 +41,14 @@ public class ExpressionMaskParser extends InputParser { super(worldEdit); } + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("="); + } + return Stream.empty(); + } + @Override public Mask parseFromInput(String input, ParserContext context) throws InputParseException { if (!input.startsWith("=")) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/LazyRegionMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/LazyRegionMaskParser.java index 82bc14d2b..29b7af7a9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/LazyRegionMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/LazyRegionMaskParser.java @@ -19,9 +19,8 @@ package com.sk89q.worldedit.extension.factory.parser.mask; -import com.google.common.collect.Lists; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.RegionMask; @@ -32,17 +31,19 @@ import java.util.List; public class LazyRegionMaskParser extends SimpleInputParser { + private final List aliases = ImmutableList.of("#dregion", "#dselection", "#dsel"); + public LazyRegionMaskParser(WorldEdit worldEdit) { super(worldEdit); } @Override public List getMatchedAliases() { - return Lists.newArrayList("#dregion", "#dselection", "#dsel"); + return aliases; } @Override - public Mask parseFromSimpleInput(String input, ParserContext context) throws InputParseException { + public Mask parseFromSimpleInput(String input, ParserContext context) { return new RegionMask(new RequestSelection()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NegateMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NegateMaskParser.java index 9e1c2e9df..e8e4ddf57 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NegateMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NegateMaskParser.java @@ -26,12 +26,25 @@ import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.internal.registry.InputParser; +import java.util.stream.Stream; + public class NegateMaskParser extends InputParser { public NegateMaskParser(WorldEdit worldEdit) { super(worldEdit); } + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("!"); + } + if (input.charAt(0) != '!') { + return Stream.empty(); + } + return worldEdit.getMaskFactory().getSuggestions(input.substring(1)).stream().map(s -> "!" + s); + } + @Override public Mask parseFromInput(String input, ParserContext context) throws InputParseException { if (!input.startsWith("!")) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NoiseMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NoiseMaskParser.java index 0cb1a85e8..40f54ebfe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NoiseMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/NoiseMaskParser.java @@ -20,13 +20,14 @@ package com.sk89q.worldedit.extension.factory.parser.mask; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.NoiseFilter; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.noise.RandomNoise; +import java.util.stream.Stream; + public class NoiseMaskParser extends InputParser { public NoiseMaskParser(WorldEdit worldEdit) { @@ -34,7 +35,18 @@ public class NoiseMaskParser extends InputParser { } @Override - public Mask parseFromInput(String input, ParserContext context) throws InputParseException { + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("%"); + } + if (input.charAt(0) != '%') { + return Stream.empty(); + } + return Stream.of("%10", "%25", "%50", "%75").filter(s -> s.startsWith(input)); + } + + @Override + public Mask parseFromInput(String input, ParserContext context) { if (!input.startsWith("%")) { return null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java index ab4882e00..ede9b6c79 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java @@ -31,12 +31,26 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.session.request.RequestExtent; +import java.util.stream.Stream; + public class OffsetMaskParser extends InputParser { public OffsetMaskParser(WorldEdit worldEdit) { super(worldEdit); } + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of(">", "<"); + } + final char firstChar = input.charAt(0); + if (firstChar != '>' && firstChar != '<') { + return Stream.empty(); + } + return worldEdit.getMaskFactory().getSuggestions(input.substring(1)).stream().map(s -> firstChar + s); + } + @Override public Mask parseFromInput(String input, ParserContext context) throws InputParseException { final char firstChar = input.charAt(0); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/RegionMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/RegionMaskParser.java index 21963835d..bd7ceaa3e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/RegionMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/RegionMaskParser.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.extension.factory.parser.mask; -import com.google.common.collect.Lists; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; @@ -32,13 +32,15 @@ import java.util.List; public class RegionMaskParser extends SimpleInputParser { + private final List aliases = ImmutableList.of("#region", "#selection", "#sel"); + public RegionMaskParser(WorldEdit worldEdit) { super(worldEdit); } @Override public List getMatchedAliases() { - return Lists.newArrayList("#region", "#selection", "#sel"); + return aliases; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java index 44e2f07a2..f5ae3244a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.extension.factory.parser.mask; -import com.google.common.collect.Lists; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.Mask; @@ -31,13 +31,15 @@ import java.util.List; public class SolidMaskParser extends SimpleInputParser { + private final List aliases = ImmutableList.of("#solid"); + public SolidMaskParser(WorldEdit worldEdit) { super(worldEdit); } @Override public List getMatchedAliases() { - return Lists.newArrayList("#solid"); + return aliases; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java index f9e0f8052..3260fa438 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.extension.factory.parser.pattern; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.pattern.BlockPattern; @@ -41,7 +42,7 @@ public class BlockCategoryPatternParser extends InputParser { @Override public Stream getSuggestions(String input) { - return BlockCategory.REGISTRY.keySet().stream().map(str -> "##" + str); + return SuggestionHelper.getBlockCategorySuggestions(input, true); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java index 4029c4359..532a981e6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.session.ClipboardHolder; +import java.util.Locale; import java.util.stream.Stream; public class ClipboardPatternParser extends InputParser { @@ -41,7 +42,27 @@ public class ClipboardPatternParser extends InputParser { @Override public Stream getSuggestions(String input) { - return Stream.of("#clipboard", "#copy"); + if (input.isEmpty()) { + return Stream.of("#clipoard"); + } + String[] offsetParts = input.split("@", 2); + String firstLower = offsetParts[0].toLowerCase(Locale.ROOT); + final boolean isClip = "#clipboard".startsWith(firstLower); + final boolean isCopy = "#copy".startsWith(firstLower); + if (isClip || isCopy) { + if (offsetParts.length == 2) { + String coords = offsetParts[1]; + if (coords.isEmpty()) { + return Stream.of(input + "[x,y,z]"); + } + } else { + if (isClip) { + return Stream.of("#clipboard", "#clipboard@[x,y,z]"); + } + return Stream.of("#copy", "#copy@[x,y,z]"); + } + } + return Stream.empty(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomPatternParser.java index 68c768954..81b1b11e3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomPatternParser.java @@ -28,6 +28,7 @@ import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.internal.registry.InputParser; import java.util.List; +import java.util.stream.Stream; public class RandomPatternParser extends InputParser { @@ -35,12 +36,35 @@ public class RandomPatternParser extends InputParser { super(worldEdit); } + @Override + public Stream getSuggestions(String input) { + String[] splits = input.split(",", -1); + List patterns = StringUtil.parseListInQuotes(splits, ',', '[', ']', true); + if (patterns.size() == 1) { + return Stream.empty(); + } + // get suggestions for the last token only + String token = patterns.get(patterns.size() - 1); + String previous = String.join(",", patterns.subList(0, patterns.size() - 1)); + if (token.matches("[0-9]+(\\.[0-9]*)?%.*")) { + String[] p = token.split("%"); + + if (p.length < 2) { + return Stream.empty(); + } else { + token = p[1]; + } + } + final List innerSuggestions = worldEdit.getPatternFactory().getSuggestions(token); + return innerSuggestions.stream().map(s -> previous + "," + s); + } + @Override public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { RandomPattern randomPattern = new RandomPattern(); - String[] splits = input.split(","); - List patterns = StringUtil.parseListInQuotes(splits, ',', '[', ']'); + String[] splits = input.split(",", -1); + List patterns = StringUtil.parseListInQuotes(splits, ',', '[', ']', true); if (patterns.size() == 1) { return null; // let a 'single'-pattern parser handle it } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java index 27423f59e..3b6dc5c1f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java @@ -29,11 +29,25 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.FuzzyBlockState; +import java.util.stream.Stream; + public class RandomStatePatternParser extends InputParser { public RandomStatePatternParser(WorldEdit worldEdit) { super(worldEdit); } + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("*"); + } + if (!input.startsWith("*")) { + return Stream.empty(); + } + + return worldEdit.getBlockFactory().getSuggestions(input.substring(1)).stream().map(s -> "*" + s); + } + @Override public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { if (!input.startsWith("*")) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java index 3bd852513..30f844611 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java @@ -25,7 +25,6 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.registry.InputParser; -import com.sk89q.worldedit.world.block.BlockType; import java.util.stream.Stream; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java index db0ee8c38..8897b115a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java @@ -20,9 +20,8 @@ package com.sk89q.worldedit.extension.factory.parser.pattern; import com.google.common.base.Splitter; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extent.Extent; @@ -32,10 +31,9 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.StateApplyingPattern; import com.sk89q.worldedit.function.pattern.TypeApplyingPattern; import com.sk89q.worldedit.internal.registry.InputParser; -import com.sk89q.worldedit.world.block.BlockState; import java.util.Map; -import java.util.Set; +import java.util.stream.Stream; public class TypeOrStateApplyingPatternParser extends InputParser { @@ -44,6 +42,30 @@ public class TypeOrStateApplyingPatternParser extends InputParser { super(worldEdit); } + @Override + public Stream getSuggestions(String input) { + if (input.isEmpty()) { + return Stream.of("^"); + } + if (!input.startsWith("^")) { + return Stream.empty(); + } + input = input.substring(1); + + String[] parts = input.split("\\[", 2); + String type = parts[0]; + + if (parts.length == 1) { + return worldEdit.getBlockFactory().getSuggestions(input).stream().map(s -> "^" + s); + } else { + if (type.isEmpty()) { + return Stream.empty(); // without knowing a type, we can't really suggest states + } else { + return SuggestionHelper.getBlockPropertySuggestions(type, parts[1]).map(s -> "^" + s); + } + } + } + @Override public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { if (!input.startsWith("^")) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index d4ec8bef8..f1b3e05aa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -20,7 +20,6 @@ package com.sk89q.worldedit.internal.registry; import static com.google.common.base.Preconditions.checkNotNull; -import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; @@ -28,11 +27,9 @@ import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.ParserContext; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.Stream; /** * An abstract implementation of a factory for internal usage. @@ -81,7 +78,9 @@ public abstract class AbstractFactory { } public List getSuggestions(String input) { - return limitByPrefix(parsers.stream().flatMap(parser -> parser.getSuggestions(input)), input); + return parsers.stream().flatMap( + p -> p.getSuggestions(input) + ).collect(Collectors.toList()); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java index 5862d9cf9..febafacc8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/InputParser.java @@ -23,8 +23,6 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; -import java.util.Collections; -import java.util.List; import java.util.stream.Stream; /** @@ -37,7 +35,7 @@ public abstract class InputParser { protected final WorldEdit worldEdit; - public InputParser(WorldEdit worldEdit) { + protected InputParser(WorldEdit worldEdit) { this.worldEdit = worldEdit; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java index 013e45958..aace1ee89 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/SimpleInputParser.java @@ -19,12 +19,12 @@ package com.sk89q.worldedit.internal.registry; -import com.google.common.collect.Lists; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import java.util.List; +import java.util.Locale; import java.util.stream.Stream; /** @@ -34,7 +34,7 @@ import java.util.stream.Stream; */ public abstract class SimpleInputParser extends InputParser { - public SimpleInputParser(WorldEdit worldEdit) { + protected SimpleInputParser(WorldEdit worldEdit) { super(worldEdit); } @@ -67,6 +67,15 @@ public abstract class SimpleInputParser extends InputParser { @Override public Stream getSuggestions(String input) { - return Stream.of(getPrimaryMatcher()); + if (input.isEmpty()) { + return Stream.of(getPrimaryMatcher()); + } + final String prefix = input.toLowerCase(Locale.ROOT); + for (String alias : getMatchedAliases()) { + if (alias.startsWith(prefix)) { + return Stream.of(alias); + } + } + return Stream.empty(); } } From ab1e09fdafa29d7e36ffb3652e7caad15f5e13ea Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 27 May 2019 00:35:26 -0400 Subject: [PATCH 156/366] Give factories a default parser. Later registered parsers will always come before the default, ensuring that the default parser is used when no other parser can match the input, and that errors may be thrown by it to signify the end of the line. --- .../sk89q/worldedit/extension/factory/BlockFactory.java | 4 +--- .../com/sk89q/worldedit/extension/factory/ItemFactory.java | 4 +--- .../com/sk89q/worldedit/extension/factory/MaskFactory.java | 4 +--- .../sk89q/worldedit/extension/factory/PatternFactory.java | 5 +---- .../extension/factory/parser/DefaultBlockParser.java | 4 +++- .../sk89q/worldedit/internal/registry/AbstractFactory.java | 7 +++++-- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java index c00583183..4f5a4fdbc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/BlockFactory.java @@ -45,9 +45,7 @@ public class BlockFactory extends AbstractFactory { * @param worldEdit the WorldEdit instance. */ public BlockFactory(WorldEdit worldEdit) { - super(worldEdit); - - register(new DefaultBlockParser(worldEdit)); + super(worldEdit, new DefaultBlockParser(worldEdit)); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java index e2a2bee29..71853f79f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/ItemFactory.java @@ -32,9 +32,7 @@ public class ItemFactory extends AbstractFactory { * @param worldEdit the WorldEdit instance. */ public ItemFactory(WorldEdit worldEdit) { - super(worldEdit); - - register(new DefaultItemParser(worldEdit)); + super(worldEdit, new DefaultItemParser(worldEdit)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java index 31b1ac2df..73df7a52d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java @@ -58,7 +58,7 @@ public final class MaskFactory extends AbstractFactory { * @param worldEdit the WorldEdit instance */ public MaskFactory(WorldEdit worldEdit) { - super(worldEdit); + super(worldEdit, new BlocksMaskParser(worldEdit)); register(new ExistingMaskParser(worldEdit)); register(new SolidMaskParser(worldEdit)); @@ -72,8 +72,6 @@ public final class MaskFactory extends AbstractFactory { register(new BlockCategoryMaskParser(worldEdit)); register(new BiomeMaskParser(worldEdit)); - - register(new BlocksMaskParser(worldEdit)); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java index 0df1dc40c..014229a3e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/PatternFactory.java @@ -44,7 +44,7 @@ public final class PatternFactory extends AbstractFactory { * @param worldEdit the WorldEdit instance */ public PatternFactory(WorldEdit worldEdit) { - super(worldEdit); + super(worldEdit, new SingleBlockPatternParser(worldEdit)); // split and parse each sub-pattern register(new RandomPatternParser(worldEdit)); @@ -54,9 +54,6 @@ public final class PatternFactory extends AbstractFactory { register(new TypeOrStateApplyingPatternParser(worldEdit)); register(new RandomStatePatternParser(worldEdit)); register(new BlockCategoryPatternParser(worldEdit)); - - // inner-most pattern: just one block - must be last - register(new SingleBlockPatternParser(worldEdit)); } } 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 4a03a5471..0bdcdc9ae 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 @@ -54,6 +54,8 @@ import java.util.Locale; import java.util.Map; import java.util.stream.Stream; +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + /** * Parses block input strings. */ @@ -209,7 +211,7 @@ public class DefaultBlockParser extends InputParser { if (input.contains(",")) { return Stream.empty(); } - return BlockType.REGISTRY.keySet().stream(); + return limitByPrefix(BlockType.REGISTRY.keySet().stream(), input).stream(); } String blockType = input.substring(0, idx); BlockType type = BlockTypes.get(blockType.toLowerCase(Locale.ROOT)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java index f1b3e05aa..a5844306d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/registry/AbstractFactory.java @@ -46,10 +46,13 @@ public abstract class AbstractFactory { * Create a new factory. * * @param worldEdit the WorldEdit instance + * @param defaultParser the parser to fall back to */ - protected AbstractFactory(WorldEdit worldEdit) { + protected AbstractFactory(WorldEdit worldEdit, InputParser defaultParser) { checkNotNull(worldEdit); + checkNotNull(defaultParser); this.worldEdit = worldEdit; + this.parsers.add(defaultParser); } /** @@ -91,6 +94,6 @@ public abstract class AbstractFactory { public void register(InputParser inputParser) { checkNotNull(inputParser); - parsers.add(inputParser); + parsers.add(parsers.size() - 1, inputParser); } } From 5e857b3547f65378af12035b2f561ea99a3e570c Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 27 May 2019 11:12:46 -0400 Subject: [PATCH 157/366] Improve parsing from registries. If multiple namespaces are present, suggestions will first suggest a namespace, then once a namespace is selected, keys within that namespace. Starting an argument with ":" will instead search across all namespaces for matching keys. --- .../command/argument/RegistryConverter.java | 12 +-- .../command/util/SuggestionHelper.java | 78 +++++++++++++------ .../factory/parser/DefaultBlockParser.java | 51 ++++++------ .../factory/parser/mask/BiomeMaskParser.java | 32 ++++---- .../registry/NamespacedRegistry.java | 29 ++++++- 5 files changed, 123 insertions(+), 79 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java index 264b1af0c..83999afa1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java @@ -20,8 +20,8 @@ package com.sk89q.worldedit.command.argument; import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.registry.Keyed; -import com.sk89q.worldedit.registry.NamespacedRegistry; import com.sk89q.worldedit.registry.Registry; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -45,8 +45,7 @@ import org.enginehub.piston.inject.Key; import java.lang.reflect.Field; import java.util.List; - -import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; +import java.util.stream.Collectors; public final class RegistryConverter implements ArgumentConverter { @@ -85,12 +84,10 @@ public final class RegistryConverter implements ArgumentConvert private final Registry registry; private final TextComponent choices; - private final boolean namespaced; private RegistryConverter(Registry registry) { this.registry = registry; this.choices = TextComponent.of("any " + registry.getName()); - this.namespaced = registry instanceof NamespacedRegistry; } @Override @@ -109,9 +106,6 @@ public final class RegistryConverter implements ArgumentConvert @Override public List getSuggestions(String input) { - if (namespaced && input.indexOf(':') < 0) { - input = "minecraft:" + input; - } - return limitByPrefix(registry.keySet().stream(), input); + return SuggestionHelper.getRegistrySuggestions(registry, input).collect(Collectors.toList()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java index acf18f041..e0014ee56 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java @@ -19,6 +19,9 @@ package com.sk89q.worldedit.command.util; +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; +import com.sk89q.worldedit.registry.Registry; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.block.BlockCategory; import com.sk89q.worldedit.world.block.BlockType; @@ -30,39 +33,32 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.enginehub.piston.converter.SuggestionHelper.byPrefix; +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + +/** + * Internal class for generating common command suggestions. + */ public final class SuggestionHelper { private SuggestionHelper() { } public static Stream getBlockCategorySuggestions(String tag, boolean allowRandom) { - final Stream allTags = BlockCategory.REGISTRY.keySet().stream().map(str -> "##" + str); - if (tag.isEmpty()) { - return allTags; + if (tag.isEmpty() || tag.equals("#")) { + return Stream.of("##", "##*"); } if (tag.startsWith("#")) { - String key; - if (tag.startsWith("##")) { - key = tag.substring(2); - if (key.isEmpty()) { - return allTags; - } - boolean anyState = false; - if (allowRandom && key.charAt(0) == '*') { - key = key.substring(1); - anyState = true; - } - if (key.indexOf(':') < 0) { - key = "minecraft:" + key; - } - String finalTag = key.toLowerCase(Locale.ROOT); - final Stream stream = BlockCategory.REGISTRY.keySet().stream().filter(s -> - s.startsWith(finalTag)); - return anyState ? stream.map(s -> "##*" + s) : stream.map(s -> "##" + s); - } else if (tag.length() == 1) { - return allTags; + if (tag.equals("##")) { + return Stream.concat(Stream.of("##*"), getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(2)).map(s -> "##" + s)); + } else if (tag.equals("##*") && allowRandom) { + return getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(3)).map(s -> "##*" + s); + } else { + boolean wild = tag.startsWith("##*") && allowRandom; + return getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(wild ? 3 : 2)).map(s -> (wild ? "##*" : "##") + s); } } return Stream.empty(); @@ -103,7 +99,7 @@ public final class SuggestionHelper { } else { Property prop = propertyMap.get(matchProp); if (prop == null) { - return Stream.empty(); + return propertyMap.keySet().stream().map(p -> lastValidInput + p); } final List values = prop.getValues().stream().map(v -> v.toString().toLowerCase(Locale.ROOT)).collect(Collectors.toList()); String matchVal = propVal[1].toLowerCase(Locale.ROOT); @@ -140,4 +136,38 @@ public final class SuggestionHelper { } return Stream.empty(); } + + public static Stream getRegistrySuggestions(Registry registry, String input) { + if (registry instanceof NamespacedRegistry) { + return getNamespacedRegistrySuggestions(((NamespacedRegistry) registry), input); + } + return limitByPrefix(registry.keySet().stream(), input).stream(); + } + + public static Stream getNamespacedRegistrySuggestions(NamespacedRegistry registry, String input) { + if (input.isEmpty() || input.equals(":")) { + final Set namespaces = registry.getKnownNamespaces(); + if (namespaces.size() == 1) { + return registry.keySet().stream(); + } else { + return namespaces.stream().map(s -> s + ":"); + } + } + if (input.startsWith(":")) { // special case - search across namespaces + final String term = input.substring(1).toLowerCase(Locale.ROOT); + Predicate search = byPrefix(term); + return registry.keySet().stream().filter(s -> search.test(s.substring(s.indexOf(':') + 1))); + } + // otherwise, we actually have some text to search + if (input.indexOf(':') < 0) { + // don't yet have namespace - search namespaces + default + final String lowerSearch = input.toLowerCase(Locale.ROOT); + String defKey = registry.getDefaultNamespace() + ":" + lowerSearch; + return Stream.concat(registry.keySet().stream().filter(s -> s.startsWith(defKey)), + registry.getKnownNamespaces().stream().filter(n -> n.startsWith(lowerSearch)).map(n -> n + ":")); + } + // have a namespace - search that + Predicate search = byPrefix(input.toLowerCase(Locale.ROOT)); + return registry.keySet().stream().filter(search); + } } 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 0bdcdc9ae..9f4402715 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 @@ -54,8 +54,6 @@ import java.util.Locale; import java.util.Map; import java.util.stream.Stream; -import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; - /** * Parses block input strings. */ @@ -111,6 +109,7 @@ public class DefaultBlockParser extends InputParser { * @param string Input string * @return Mapped string */ + @SuppressWarnings("ConstantConditions") private String woolMapper(String string) { switch (string.toLowerCase(Locale.ROOT)) { case "white": @@ -191,7 +190,7 @@ public class DefaultBlockParser extends InputParser { } catch (NoMatchException e) { throw e; // Pass-through } catch (Exception e) { - e.printStackTrace(); + WorldEdit.logger.warn("Unknown state '" + parseableData + "'", e); throw new NoMatchException("Unknown state '" + parseableData + "'"); } } @@ -204,14 +203,7 @@ public class DefaultBlockParser extends InputParser { public Stream getSuggestions(String input) { final int idx = input.lastIndexOf('['); if (idx < 0) { - if (input.indexOf(':') == -1) { - String key = ("minecraft:" + input).toLowerCase(Locale.ROOT); - return BlockType.REGISTRY.keySet().stream().filter(s -> s.startsWith(key)); - } - if (input.contains(",")) { - return Stream.empty(); - } - return limitByPrefix(BlockType.REGISTRY.keySet().stream(), input).stream(); + return SuggestionHelper.getNamespacedRegistrySuggestions(BlockType.REGISTRY, input); } String blockType = input.substring(0, idx); BlockType type = BlockTypes.get(blockType.toLowerCase(Locale.ROOT)); @@ -238,8 +230,10 @@ public class DefaultBlockParser extends InputParser { // Legacy matcher if (context.isTryingLegacy()) { try { - String[] split = blockAndExtraData[0].split(":"); - if (split.length == 1) { + String[] split = blockAndExtraData[0].split(":", 2); + if (split.length == 0) { + throw new InputParseException("Invalid colon."); + } else if (split.length == 1) { state = LegacyMapper.getInstance().getBlockFromLegacy(Integer.parseInt(split[0])); } else { state = LegacyMapper.getInstance().getBlockFromLegacy(Integer.parseInt(split[0]), Integer.parseInt(split[1])); @@ -247,7 +241,7 @@ public class DefaultBlockParser extends InputParser { if (state != null) { blockType = state.getBlockType(); } - } catch (NumberFormatException e) { + } catch (NumberFormatException ignored) { } } @@ -310,23 +304,15 @@ public class DefaultBlockParser extends InputParser { } else { // Attempt to lookup a block from ID or name. blockType = BlockTypes.get(typeString.toLowerCase(Locale.ROOT)); + } - if (blockType == null) { - throw new NoMatchException("Does not match a valid block type: '" + input + "'"); - } + if (blockType == null) { + throw new NoMatchException("Does not match a valid block type: '" + input + "'"); } blockStates.putAll(parseProperties(blockType, stateProperties, context)); - if (!context.isPreferringWildcard()) { - // No wildcards allowed => eliminate them. (Start with default state) - state = blockType.getDefaultState(); - for (Map.Entry, Object> blockState : blockStates.entrySet()) { - @SuppressWarnings("unchecked") - Property objProp = (Property) blockState.getKey(); - state = state.with(objProp, blockState.getValue()); - } - } else { + if (context.isPreferringWildcard()) { FuzzyBlockState.Builder fuzzyBuilder = FuzzyBlockState.builder(); fuzzyBuilder.type(blockType); for (Map.Entry, Object> blockState : blockStates.entrySet()) { @@ -335,8 +321,20 @@ public class DefaultBlockParser extends InputParser { fuzzyBuilder.withProperty(objProp, blockState.getValue()); } state = fuzzyBuilder.build(); + } else { + // No wildcards allowed => eliminate them. (Start with default state) + state = blockType.getDefaultState(); + for (Map.Entry, Object> blockState : blockStates.entrySet()) { + @SuppressWarnings("unchecked") + Property objProp = (Property) blockState.getKey(); + state = state.with(objProp, blockState.getValue()); + } } } + // this should be impossible but IntelliJ isn't that smart + if (blockType == null) { + throw new NoMatchException("Does not match a valid block type: '" + input + "'"); + } // Check if the item is allowed if (context.isRestricted()) { @@ -369,6 +367,7 @@ public class DefaultBlockParser extends InputParser { } return new MobSpawnerBlock(state, mobName); } else { + //noinspection ConstantConditions return new MobSpawnerBlock(state, EntityTypes.PIG.getId()); } } else if (blockType == BlockTypes.PLAYER_HEAD || blockType == BlockTypes.PLAYER_WALL_HEAD) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java index db0ab21e7..9e38e2e82 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java @@ -21,22 +21,20 @@ package com.sk89q.worldedit.extension.factory.parser.mask; import com.google.common.base.Splitter; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; -import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.function.mask.BiomeMask2D; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.world.biome.BiomeType; -import com.sk89q.worldedit.world.biome.Biomes; -import com.sk89q.worldedit.world.registry.BiomeRegistry; -import java.util.Collection; +import java.util.Arrays; import java.util.HashSet; -import java.util.Locale; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; public class BiomeMaskParser extends InputParser { @@ -47,20 +45,20 @@ public class BiomeMaskParser extends InputParser { @Override public Stream getSuggestions(String input) { - final Stream allBiomes = BiomeType.REGISTRY.keySet().stream().map(biomeType -> "$" + biomeType); if (input.isEmpty()) { - return allBiomes; + return Stream.of("$"); } if (input.charAt(0) == '$') { - String key = input.substring(1); - if (key.isEmpty()) { - return allBiomes; + input = input.substring(1); + final int lastTermIdx = input.lastIndexOf(','); + if (lastTermIdx <= 0) { + return SuggestionHelper.getNamespacedRegistrySuggestions(BiomeType.REGISTRY, input).map(s -> "$" + s); } - if (key.indexOf(':') < 0) { - key = "minecraft:" + key; - } - String biomeId = key.toLowerCase(Locale.ROOT); - return BiomeType.REGISTRY.keySet().stream().filter(s -> s.startsWith(biomeId)).map(s -> "$" + s); + String prev = input.substring(0, lastTermIdx) + ","; + Set prevBiomes = Arrays.stream(prev.split(",", 0)).collect(Collectors.toSet()); + String search = input.substring(lastTermIdx + 1); + return SuggestionHelper.getNamespacedRegistrySuggestions(BiomeType.REGISTRY, search) + .filter(s -> !prevBiomes.contains(s)).map(s -> "$" + prev + s); } return Stream.empty(); } @@ -72,10 +70,8 @@ public class BiomeMaskParser extends InputParser { } Set biomes = new HashSet<>(); - BiomeRegistry biomeRegistry = worldEdit.getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); - Collection knownBiomes = BiomeType.REGISTRY.values(); for (String biomeName : Splitter.on(",").split(input.substring(1))) { - BiomeType biome = Biomes.findBiomeByName(knownBiomes, biomeName, biomeRegistry); + BiomeType biome = BiomeType.REGISTRY.get(biomeName); if (biome == null) { throw new InputParseException("Unknown biome '" + biomeName + '\''); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java index 4519bbc88..893cbd018 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/registry/NamespacedRegistry.java @@ -23,9 +23,13 @@ import static com.google.common.base.Preconditions.checkState; import static java.util.Objects.requireNonNull; import javax.annotation.Nullable; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; public final class NamespacedRegistry extends Registry { private static final String MINECRAFT_NAMESPACE = "minecraft"; + private final Set knownNamespaces = new HashSet<>(); private final String defaultNamespace; public NamespacedRegistry(final String name) { @@ -46,8 +50,29 @@ public final class NamespacedRegistry extends Registry { @Override public V register(final String key, final V value) { requireNonNull(key, "key"); - checkState(key.indexOf(':') > -1, "key is not namespaced"); - return super.register(key, value); + final int i = key.indexOf(':'); + checkState(i > 0, "key is not namespaced"); + final V registered = super.register(key, value); + knownNamespaces.add(key.substring(0, i)); + return registered; + } + + /** + * Get a set of the namespaces of all registered keys. + * + * @return set of namespaces + */ + public Set getKnownNamespaces() { + return Collections.unmodifiableSet(knownNamespaces); + } + + /** + * Get the default namespace for this registry. + * + * @return the default namespace + */ + public String getDefaultNamespace() { + return defaultNamespace; } private String orDefaultNamespace(final String key) { From 27b58f4e850e6f1c15e18ff152746f4f5091c187 Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 28 May 2019 16:07:29 -0400 Subject: [PATCH 158/366] Add suggestions for items. --- .../extension/factory/parser/DefaultItemParser.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java index e325b24a1..450538f28 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.extension.factory.parser; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.internal.registry.InputParser; @@ -39,11 +40,7 @@ public class DefaultItemParser extends InputParser { @Override public Stream getSuggestions(String input) { - if (input.indexOf(':') == -1) { - input = "minecraft:" + input; - } - String key = input; - return ItemType.REGISTRY.keySet().stream().filter(s -> s.startsWith(key)); + return SuggestionHelper.getNamespacedRegistrySuggestions(ItemType.REGISTRY, input); } @Override @@ -54,7 +51,9 @@ public class DefaultItemParser extends InputParser { try { String[] split = input.split(":"); ItemType type; - if (split.length == 1) { + if (split.length == 0) { + throw new InputParseException("Invalid colon."); + } else if (split.length == 1) { type = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(split[0])); } else { type = LegacyMapper.getInstance().getItemFromLegacy(Integer.parseInt(split[0]), Integer.parseInt(split[1])); From ec3648e521d00d1ca9a6f0d10783d754ac44eaef Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 29 May 2019 21:38:37 -0400 Subject: [PATCH 159/366] Wrap and unwrap. Exceptions are fun. --- .../main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java | 2 +- .../internal/command/exception/ExceptionConverterHelper.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) 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 570ef30be..b53d36b01 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 @@ -131,7 +131,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // register this so we can load world-dependent data right as the first world is loading if (worldInitListener != null) { - getLogger().warning("Server reload detected. This may cause various issues with WorldEdit and dependant plugins."); + getLogger().warning("Server reload detected. This may cause various issues with WorldEdit and dependent plugins."); try { // these don't stick around between reload loadAdapter(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java index 99a9bce68..42959c5fb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/ExceptionConverterHelper.java @@ -76,6 +76,9 @@ public abstract class ExceptionConverterHelper implements ExceptionConverter { if (e.getCause() instanceof CommandException) { throw (CommandException) e.getCause(); } + if (e.getCause() instanceof com.sk89q.minecraft.util.commands.CommandException) { + throw new CommandException(e.getCause(), ImmutableList.of()); + } throw new CommandExecutionException(e, ImmutableList.of()); } catch (IllegalArgumentException | IllegalAccessException e) { throw new CommandExecutionException(e, ImmutableList.of()); From 6ad274677f07d05d83d214974ee2532073699add Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 29 May 2019 23:15:00 -0400 Subject: [PATCH 160/366] Don't require command for CUI init. --- .../sk89q/worldedit/bukkit/CUIChannelListener.java | 5 +++-- .../main/java/com/sk89q/worldedit/LocalSession.java | 13 +++++++++---- .../forge/net/handler/WECUIPacketHandler.java | 6 ++++-- .../sk89q/worldedit/sponge/CUIChannelHandler.java | 6 ++++-- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/CUIChannelListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/CUIChannelListener.java index 23b190616..8767e9fe9 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/CUIChannelListener.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/CUIChannelListener.java @@ -41,8 +41,9 @@ public class CUIChannelListener implements PluginMessageListener { public void onPluginMessageReceived(String channel, Player player, byte[] message) { LocalSession session = plugin.getSession(player); String text = new String(message, UTF_8_CHARSET); - session.handleCUIInitializationMessage(text); - session.describeCUI(plugin.wrapPlayer(player)); + final BukkitPlayer actor = plugin.wrapPlayer(player); + session.handleCUIInitializationMessage(text, actor); + session.describeCUI(actor); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index b0c1ebd45..5dd9aabee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -782,9 +782,9 @@ public class LocalSession { * * @param text the message */ - public void handleCUIInitializationMessage(String text) { + public void handleCUIInitializationMessage(String text, Actor actor) { checkNotNull(text); - if (this.failedCuiAttempts > 3) { + if (this.hasCUISupport || this.failedCuiAttempts > 3) { return; } @@ -794,13 +794,18 @@ public class LocalSession { this.failedCuiAttempts ++; return; } - setCUISupport(true); + + int version; try { - setCUIVersion(Integer.parseInt(split[1])); + version = Integer.parseInt(split[1]); } catch (NumberFormatException e) { WorldEdit.logger.warn("Error while reading CUI init message: " + e.getMessage()); this.failedCuiAttempts ++; + return; } + setCUISupport(true); + setCUIVersion(version); + dispatchCUISelection(actor); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java index 541577e1f..5273887ea 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.forge.net.handler; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.forge.ForgePlayer; import com.sk89q.worldedit.forge.ForgeWorldEdit; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayerMP; @@ -62,8 +63,9 @@ public final class WECUIPacketHandler { } String text = event.getPayload().toString(UTF_8_CHARSET); - session.handleCUIInitializationMessage(text); - session.describeCUI(adaptPlayer(player)); + final ForgePlayer actor = adaptPlayer(player); + session.handleCUIInitializationMessage(text, actor); + session.describeCUI(actor); } public static void callProcessPacket(ClientCustomPayloadEvent event) { diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CUIChannelHandler.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CUIChannelHandler.java index 7be50e8d1..3e3fb44e1 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CUIChannelHandler.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CUIChannelHandler.java @@ -57,8 +57,10 @@ public class CUIChannelHandler implements RawDataListener { return; } - session.handleCUIInitializationMessage(new String(data.readBytes(data.available()), StandardCharsets.UTF_8)); - session.describeCUI(SpongeWorldEdit.inst().wrapPlayer(player)); + final SpongePlayer actor = SpongeWorldEdit.inst().wrapPlayer(player); + session.handleCUIInitializationMessage(new String(data.readBytes(data.available()), StandardCharsets.UTF_8), + actor); + session.describeCUI(actor); } } } From 4e43595c99c51750a617ffce382672927df15dcb Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 31 May 2019 11:24:38 -0400 Subject: [PATCH 161/366] Fix builds maybe. --- worldedit-bukkit/build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 8076e2ca1..74dfe5db3 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -17,12 +17,12 @@ configurations.all { Configuration it -> dependencies { compile project(':worldedit-core') compile project(':worldedit-libs:bukkit') - compile 'com.sk89q:dummypermscompat:1.10' compile 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz - compile 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' - compile "io.papermc:paperlib:1.0.2" - compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' - compile 'org.bstats:bstats-bukkit:1.4' + compileOnly 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' + compileOnly "io.papermc:paperlib:1.0.2" + compileOnly 'com.sk89q:dummypermscompat:1.10' + compileOnly 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' + compileOnly 'org.bstats:bstats-bukkit:1.4' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } From 44ee1546b79ad61de8f4b0f644697dea40f81b65 Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 31 May 2019 11:48:08 -0400 Subject: [PATCH 162/366] Apparently CB uses this. --- .../main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b53d36b01..18a7d69d2 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 @@ -89,7 +89,7 @@ import static com.google.common.base.Preconditions.checkNotNull; public class WorldEditPlugin extends JavaPlugin implements TabCompleter { private static final Logger log = LoggerFactory.getLogger(WorldEditPlugin.class); - static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; + public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; private static WorldEditPlugin INSTANCE; private static WorldInitListener worldInitListener = null; From 59447c6ee313a1de63d52640af47393fb60604ad Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 31 May 2019 13:53:28 -0400 Subject: [PATCH 163/366] Gradle sucks. --- worldedit-bukkit/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 74dfe5db3..17cdc5f6e 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'maven' repositories { maven { url "https://hub.spigotmc.org/nexus/content/groups/public" } maven { url "https://repo.codemc.org/repository/maven-public" } - maven { url 'https://papermc.io/repo/repository/maven-public/' } + maven { url "https://papermc.io/repo/repository/maven-public/" } } configurations.all { Configuration it -> @@ -19,10 +19,10 @@ dependencies { compile project(':worldedit-libs:bukkit') compile 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz compileOnly 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' - compileOnly "io.papermc:paperlib:1.0.2" + compile 'io.papermc:paperlib:1.0.2' compileOnly 'com.sk89q:dummypermscompat:1.10' - compileOnly 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' - compileOnly 'org.bstats:bstats-bukkit:1.4' + compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' + compile 'org.bstats:bstats-bukkit:1.4' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } From 38607f387ad57c336e58df215a63f668f6905805 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 1 Jun 2019 15:53:03 +1000 Subject: [PATCH 164/366] Added a permission node to set NBT data, allowing servers to disallow NBT interactions. --- .../java/com/sk89q/worldedit/LocalSession.java | 9 +++++++++ .../extent/world/SurvivalModeExtent.java | 16 +++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 5dd9aabee..c71e7d1aa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -232,6 +232,9 @@ public class LocalSession { newEditSession.enableStandardMode(); newEditSession.setReorderMode(reorderMode); newEditSession.setFastMode(fastMode); + if (newEditSession.getSurvivalExtent() != null) { + newEditSession.getSurvivalExtent().setStripNbt(!player.hasPermission("worldedit.setnbt")); + } editSession.undo(newEditSession); } return editSession; @@ -257,6 +260,9 @@ public class LocalSession { newEditSession.enableStandardMode(); newEditSession.setReorderMode(reorderMode); newEditSession.setFastMode(fastMode); + if (newEditSession.getSurvivalExtent() != null) { + newEditSession.getSurvivalExtent().setStripNbt(!player.hasPermission("worldedit.setnbt")); + } editSession.redo(newEditSession); } ++historyPointer; @@ -887,6 +893,9 @@ public class LocalSession { editSession.setFastMode(fastMode); editSession.setReorderMode(reorderMode); editSession.setMask(mask); + if (editSession.getSurvivalExtent() != null) { + editSession.getSurvivalExtent().setStripNbt(!player.hasPermission("worldedit.setnbt")); + } return editSession; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java index 56f136c39..9f2c3a4f6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/SurvivalModeExtent.java @@ -40,6 +40,7 @@ public class SurvivalModeExtent extends AbstractDelegateExtent { private final World world; private boolean toolUse = false; + private boolean stripNbt = false; /** * Create a new instance. @@ -78,13 +79,26 @@ public class SurvivalModeExtent extends AbstractDelegateExtent { this.toolUse = toolUse; } + public boolean hasStripNbt() { + return stripNbt; + } + + public void setStripNbt(boolean stripNbt) { + this.stripNbt = stripNbt; + } + @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { if (toolUse && block.getBlockType().getMaterial().isAir()) { world.simulateBlockMine(location); return true; } else { - return super.setBlock(location, block); + // Can't be an inlined check due to inconsistent generic return type + if (stripNbt) { + return super.setBlock(location, block.toBaseBlock(null)); + } else { + return super.setBlock(location, block); + } } } From 620992dd574daef42e1eef17e720c4514f539960 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 1 Jun 2019 01:51:06 -0700 Subject: [PATCH 165/366] Update Piston to 0.4.0 for bugfixes --- .../sk89q/worldedit/command/util/PermissionCondition.java | 5 +++-- worldedit-libs/build.gradle | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java index 48b6acc16..a3ba83c6f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.command.util; import com.sk89q.worldedit.extension.platform.Actor; import org.enginehub.piston.Command; import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; import java.util.Set; @@ -41,8 +42,8 @@ public final class PermissionCondition implements Command.Condition { } @Override - public boolean satisfied(CommandParameters parameters) { - return parameters.injectedValue(ACTOR_KEY) + public boolean satisfied(InjectedValueAccess context) { + return context.injectedValue(ACTOR_KEY) .map(actor -> permissions.stream().anyMatch(actor::hasPermission)) .orElse(false); } diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index a1954e09d..4f07f5aae 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -90,13 +90,14 @@ configure(subprojects + project("core:ap")) { def textExtrasVersion = "3.0.2" project("core") { - def textVersion = "3.0.0" - def pistonVersion = '0.3.0' + def textVersion = "3.0.1" + def pistonVersion = '0.4.0' dependencies { shade "net.kyori:text-api:$textVersion" shade "net.kyori:text-serializer-gson:$textVersion" shade "net.kyori:text-serializer-legacy:$textVersion" + shade "net.kyori:text-serializer-plain:$textVersion" shade('com.sk89q:jchronic:0.2.4a') { exclude(group: "junit", module: "junit") } From 9099a17fe569cab302fcaf35e7d3775ecdc7d43c Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 27 May 2019 18:26:20 -0400 Subject: [PATCH 166/366] Some command refactoring. Switch usages of page args to -p flag. --- .../worldedit/command/BiomeCommands.java | 35 +++-- .../worldedit/command/BrushCommands.java | 8 +- .../worldedit/command/ChunkCommands.java | 5 +- .../worldedit/command/GeneralCommands.java | 127 +++++++++--------- .../worldedit/command/SchematicCommands.java | 123 ++++++++++------- .../worldedit/command/UtilityCommands.java | 3 +- .../worldedit/command/WorldEditCommands.java | 3 +- .../CommandPermissionsConditionGenerator.java | 1 - .../command/util/PrintCommandHelp.java | 2 +- .../util/WorldEditAsyncCommandBuilder.java | 27 ++++ .../platform/PlatformCommandManager.java | 4 +- .../command/CommandRegistrationHandler.java | 3 - .../sk89q/worldedit/world/item/ItemType.java | 11 +- 13 files changed, 211 insertions(+), 141 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index ef6e38981..4e2b714e2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -26,7 +26,9 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.function.FlatRegionFunction; import com.sk89q.worldedit.function.FlatRegionMaskingFilter; @@ -50,10 +52,10 @@ import com.sk89q.worldedit.world.registry.BiomeRegistry; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; import java.util.HashSet; -import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -77,17 +79,28 @@ public class BiomeCommands { desc = "Gets all biomes available." ) @CommandPermissions("worldedit.biome.list") - public void biomeList(Player player, - @Arg(desc = "Page number.", def = "1") - int page) throws WorldEditException { - BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() - .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); + public void biomeList(Actor actor, + @ArgFlag(name = 'p', desc = "Page number.", def = "1") + int page) { + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> { + BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); - PaginationBox paginationBox = PaginationBox.fromStrings("Available Biomes", "/biomelist %page%", - BiomeType.REGISTRY.values().stream() - .map(biomeRegistry::getData).filter(Objects::nonNull) - .map(BiomeData::getName).collect(Collectors.toList())); - player.print(paginationBox.create(page)); + PaginationBox paginationBox = PaginationBox.fromStrings("Available Biomes", "/biomelist -p %page%", + BiomeType.REGISTRY.values().stream() + .map(biomeType -> { + String id = biomeType.getId(); + final BiomeData data = biomeRegistry.getData(biomeType); + if (data != null) { + String name = data.getName(); + return id + " (" + name + ")"; + } else { + return id; + } + }) + .collect(Collectors.toList())); + return paginationBox.create(page); + }, null); } @Command( 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 b6433a206..ae27b9505 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 @@ -90,7 +90,7 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.sphere") public void sphereBrush(Player player, LocalSession session, @Arg(desc = "The pattern of blocks to set") - Pattern fill, + Pattern pattern, @Arg(desc = "The radius of the sphere", def = "2") double radius, @Switch(name = 'h', desc = "Create hollow spheres instead") @@ -98,7 +98,7 @@ public class BrushCommands { worldEdit.checkMaxBrushRadius(radius); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); - tool.setFill(fill); + tool.setFill(pattern); tool.setSize(radius); if (hollow) { @@ -118,7 +118,7 @@ public class BrushCommands { @CommandPermissions("worldedit.brush.cylinder") public void cylinderBrush(Player player, LocalSession session, @Arg(desc = "The pattern of blocks to set") - Pattern fill, + Pattern pattern, @Arg(desc = "The radius of the cylinder", def = "2") double radius, @Arg(desc = "The height of the cylinder", def = "1") @@ -129,7 +129,7 @@ public class BrushCommands { worldEdit.checkMaxBrushRadius(height); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); - tool.setFill(fill); + tool.setFill(pattern); tool.setSize(radius); if (hollow) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index 8dc99dc15..3c097b992 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -39,6 +39,7 @@ import com.sk89q.worldedit.world.storage.McRegionChunkStore; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; import java.io.FileOutputStream; import java.io.IOException; @@ -86,10 +87,10 @@ public class ChunkCommands { ) @CommandPermissions("worldedit.listchunks") public void listChunks(Player player, LocalSession session, - @Arg(desc = "Page number.", def = "1") int page) throws WorldEditException { + @ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException { Set chunks = session.getSelection(player.getWorld()).getChunks(); - PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks %page%", + PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks -p %page%", chunks.stream().map(BlockVector2::toString).collect(Collectors.toList())); player.print(paginationBox.create(page)); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index a84c3d1a0..34a56b8e5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -19,25 +19,35 @@ package com.sk89q.worldedit.command; -import com.google.common.collect.Sets; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.command.util.AsyncCommandBuilder; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.item.ItemType; -import com.sk89q.worldedit.world.item.ItemTypes; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.Callable; + import static com.google.common.base.Preconditions.checkNotNull; /** @@ -65,7 +75,7 @@ public class GeneralCommands { @CommandPermissions("worldedit.limit") public void limit(Player player, LocalSession session, @Arg(desc = "The limit to set", def = "") - Integer limit) throws WorldEditException { + Integer limit) { LocalConfiguration config = worldEdit.getConfiguration(); boolean mayDisable = player.hasPermission("worldedit.limit.unrestricted"); @@ -79,12 +89,8 @@ public class GeneralCommands { } session.setBlockChangeLimit(limit); - - if (limit != config.defaultChangeLimit) { - player.print("Block change limit set to " + limit + ". (Use //limit to go back to the default.)"); - } else { - player.print("Block change limit set to " + limit + "."); - } + player.print("Block change limit set to " + limit + "." + + (limit == config.defaultChangeLimit ? "" : " (Use //limit to go back to the default.)")); } @Command( @@ -94,8 +100,7 @@ public class GeneralCommands { @CommandPermissions("worldedit.timeout") public void timeout(Player player, LocalSession session, @Arg(desc = "The timeout time to set", def = "") - Integer limit) throws WorldEditException { - + Integer limit) { LocalConfiguration config = worldEdit.getConfiguration(); boolean mayDisable = player.hasPermission("worldedit.timeout.unrestricted"); @@ -108,12 +113,8 @@ public class GeneralCommands { } session.setTimeout(limit); - - if (limit != config.calculationTimeout) { - player.print("Timeout time set to " + limit + " ms. (Use //timeout to go back to the default.)"); - } else { - player.print("Timeout time set to " + limit + " ms."); - } + player.print("Timeout time set to " + limit + " ms." + + (limit == config.calculationTimeout ? "" : " (Use //timeout to go back to the default.)")); } @Command( @@ -123,7 +124,7 @@ public class GeneralCommands { @CommandPermissions("worldedit.fast") public void fast(Player player, LocalSession session, @Arg(desc = "The new fast mode state", def = "") - Boolean fastMode) throws WorldEditException { + Boolean fastMode) { boolean hasFastMode = session.hasFastMode(); if (fastMode != null && fastMode == hasFastMode) { player.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + "."); @@ -146,7 +147,7 @@ public class GeneralCommands { @CommandPermissions("worldedit.reorder") public void reorderMode(Player player, LocalSession session, @Arg(desc = "The reorder mode", def = "") - EditSession.ReorderMode reorderMode) throws WorldEditException { + EditSession.ReorderMode reorderMode) { if (reorderMode == null) { player.print("The reorder mode is " + session.getReorderMode().getDisplayName()); } else { @@ -190,9 +191,9 @@ public class GeneralCommands { @CommandPermissions("worldedit.global-mask") public void gmask(Player player, LocalSession session, @Arg(desc = "The mask to set", def = "") - Mask mask) throws WorldEditException { + Mask mask) { if (mask == null) { - session.setMask((Mask) null); + session.setMask(null); player.print("Global mask disabled."); } else { session.setMask(mask); @@ -205,8 +206,7 @@ public class GeneralCommands { aliases = {"/toggleplace"}, desc = "Switch between your position and pos1 for placement" ) - public void togglePlace(Player player, LocalSession session) throws WorldEditException { - + public void togglePlace(Player player, LocalSession session) { if (session.togglePlacementPosition()) { player.print("Now placing at pos #1."); } else { @@ -220,41 +220,48 @@ public class GeneralCommands { desc = "Search for an item" ) public void searchItem(Actor actor, - @Arg(desc = "Item query") - String query, + @Arg(desc = "Search query", variable = true) + List query, @Switch(name = 'b', desc = "Only search for blocks") boolean blocksOnly, @Switch(name = 'i', desc = "Only search for items") - boolean itemsOnly) throws WorldEditException { - ItemType type = ItemTypes.get(query); + boolean itemsOnly, + @ArgFlag(name = 'p', desc = "Page of results to return", def = "1") + int page) { + String search = String.join(" ", query); + if (search.length() <= 2) { + actor.printError("Enter a longer search string (len > 2)."); + return; + } + if (blocksOnly && itemsOnly) { + actor.printError("You cannot use both the 'b' and 'i' flags simultaneously."); + return; + } - if (type != null) { - actor.print(type.getId() + " (" + type.getName() + ")"); - } else { - if (query.length() <= 2) { - actor.printError("Enter a longer search string (len > 2)."); - return; - } + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, new ItemSearcher(search, blocksOnly, itemsOnly, page), + "(Please wait... searching items.)"); + } - if (!blocksOnly && !itemsOnly) { - actor.print("Searching for: " + query); - } else if (blocksOnly && itemsOnly) { - actor.printError("You cannot use both the 'b' and 'i' flags simultaneously."); - return; - } else if (blocksOnly) { - actor.print("Searching for blocks: " + query); - } else { - actor.print("Searching for items: " + query); - } + private static class ItemSearcher implements Callable { + private final boolean blocksOnly; + private final boolean itemsOnly; + private final String search; + private final int page; - int found = 0; + ItemSearcher(String search, boolean blocksOnly, boolean itemsOnly, int page) { + this.blocksOnly = blocksOnly; + this.itemsOnly = itemsOnly; + this.search = search; + this.page = page; + } + @Override + public Component call() throws Exception { + String command = "/searchitem " + (blocksOnly ? "-b " : "") + (itemsOnly ? "-i " : "") + "-p %page% " + search; + Map results = new TreeMap<>(); + String idMatch = search.replace(' ', '_'); + String nameMatch = search.toLowerCase(Locale.ROOT); for (ItemType searchType : ItemType.REGISTRY) { - if (found >= 15) { - actor.print("Too many results!"); - break; - } - if (blocksOnly && !searchType.hasBlockType()) { continue; } @@ -262,20 +269,16 @@ public class GeneralCommands { if (itemsOnly && searchType.hasBlockType()) { continue; } - - for (String alias : Sets.newHashSet(searchType.getId(), searchType.getName())) { - if (alias.contains(query)) { - actor.print(searchType.getId() + " (" + searchType.getName() + ")"); - ++found; - break; - } + final String id = searchType.getId(); + String name = searchType.getName(); + final boolean hasName = !name.equals(id); + name = name.toLowerCase(Locale.ROOT); + if (id.contains(idMatch) || (hasName && name.contains(nameMatch))) { + results.put(id, name + (hasName ? " (" + id + ")" : "")); } } - - if (found == 0) { - actor.printError("No items found."); - } + List list = new ArrayList<>(results.values()); + return PaginationBox.fromStrings("Search results for '" + search + "'", command, list).create(page); } } - } 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 7a942567a..47f3daf9e 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 @@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.AsyncCommandBuilder; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -39,8 +40,10 @@ import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.formatting.component.CodeFormat; +import com.sk89q.worldedit.util.formatting.component.ErrorFormat; import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.component.SchematicPaginationBox; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; @@ -124,7 +127,7 @@ public class SchematicCommands { .sendMessageAfterDelay("(Please wait... loading schematic.)") .onSuccess(TextComponent.of(filename, TextColor.GOLD) .append(TextComponent.of(" loaded. Paste it with ", TextColor.LIGHT_PURPLE)) - .append(CodeFormat.wrap("//paste").clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//paste"))), + .append(CodeFormat.wrap("//paste").clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "//paste"))), session::setClipboard) .onFailure("Failed to load schematic", worldEdit.getPlatformManager().getPlatformCommandManager().getExceptionConverter()) .buildAndExec(worldEdit.getExecutorService()); @@ -257,59 +260,17 @@ public class SchematicCommands { @Switch(name = 'd', desc = "Sort by date, oldest first") boolean oldFirst, @Switch(name = 'n', desc = "Sort by date, newest first") - boolean newFirst) throws WorldEditException { + boolean newFirst) { if (oldFirst && newFirst) { throw new StopExecutionException(TextComponent.of("Cannot sort by oldest and newest.")); } - File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().saveDir); - List fileList = allFiles(dir); - - if (fileList == null || fileList.isEmpty()) { - actor.printError("No schematics found."); - return; - } - - File[] files = new File[fileList.size()]; - fileList.toArray(files); - + final String saveDir = worldEdit.getConfiguration().saveDir; final int sortType = oldFirst ? -1 : newFirst ? 1 : 0; - // cleanup file list - Arrays.sort(files, (f1, f2) -> { - // http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified - int res; - if (sortType == 0) { // use name by default - int p = f1.getParent().compareTo(f2.getParent()); - if (p == 0) { // same parent, compare names - res = f1.getName().compareTo(f2.getName()); - } else { // different parent, sort by that - res = p; - } - } else { - res = Long.compare(f1.lastModified(), f2.lastModified()); // use date if there is a flag - if (sortType == 1) res = -res; // flip date for newest first instead of oldest first - } - return res; - }); + final String pageCommand = actor.isPlayer() + ? "//schem list -p %page%" + (sortType == -1 ? " -d" : sortType == 1 ? " -n" : "") : null; - String pageCommand = actor.isPlayer() ? "//schem list -p %page%" + (oldFirst ? " -d" : newFirst ? " -n" : "") : null; - PaginationBox paginationBox = new SchematicPaginationBox(worldEdit.getConfiguration().saveDir, files, pageCommand); - actor.print(paginationBox.create(page)); - } - - private List allFiles(File root) { - File[] files = root.listFiles(); - if (files == null) return null; - List fileList = new ArrayList<>(); - for (File f : files) { - if (f.isDirectory()) { - List subFiles = allFiles(f); - if (subFiles == null) continue; // empty subdir - fileList.addAll(subFiles); - } else { - fileList.add(f); - } - } - return fileList; + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, + new SchematicListTask(saveDir, sortType, page, pageCommand), "(Please wait... gathering schematic list.)"); } private static class SchematicLoadTask implements Callable { @@ -379,4 +340,68 @@ public class SchematicCommands { return null; } } + + private static class SchematicListTask implements Callable { + private final String prefix; + private final int sortType; + private final int page; + private final File rootDir; + private final String pageCommand; + + SchematicListTask(String prefix, int sortType, int page, String pageCommand) { + this.prefix = prefix; + this.sortType = sortType; + this.page = page; + this.rootDir = WorldEdit.getInstance().getWorkingDirectoryFile(prefix); + this.pageCommand = pageCommand; + } + + @Override + public Component call() throws Exception { + List fileList = allFiles(rootDir); + + if (fileList == null || fileList.isEmpty()) { + return ErrorFormat.wrap("No schematics found."); + } + + File[] files = new File[fileList.size()]; + fileList.toArray(files); + // cleanup file list + Arrays.sort(files, (f1, f2) -> { + // http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified + int res; + if (sortType == 0) { // use name by default + int p = f1.getParent().compareTo(f2.getParent()); + if (p == 0) { // same parent, compare names + res = f1.getName().compareTo(f2.getName()); + } else { // different parent, sort by that + res = p; + } + } else { + res = Long.compare(f1.lastModified(), f2.lastModified()); // use date if there is a flag + if (sortType == 1) res = -res; // flip date for newest first instead of oldest first + } + return res; + }); + + PaginationBox paginationBox = new SchematicPaginationBox(prefix, files, pageCommand); + return paginationBox.create(page); + } + } + + private static List allFiles(File root) { + File[] files = root.listFiles(); + if (files == null) return null; + List fileList = new ArrayList<>(); + for (File f : files) { + if (f.isDirectory()) { + List subFiles = allFiles(f); + if (subFiles == null) continue; // empty subdir + fileList.addAll(subFiles); + } else { + fileList.add(f); + } + } + return fileList; + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 3b6217154..4388b129e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -61,6 +61,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; import java.text.DecimalFormat; @@ -517,7 +518,7 @@ public class UtilityCommands { public void help(Actor actor, @Switch(name = 's', desc = "List sub-commands of the given command, if applicable") boolean listSubCommands, - @Arg(desc = "The page to retrieve", def = "1") + @ArgFlag(name = 'p', desc = "The page to retrieve", def = "1") int page, @Arg(desc = "The command to retrieve help for", def = "", variable = true) List command) throws WorldEditException { 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 1a383a767..02ab382a4 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 @@ -39,6 +39,7 @@ import com.sk89q.worldedit.util.report.SystemInfoReport; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; 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; @@ -159,7 +160,7 @@ public class WorldEditCommands { public void help(Actor actor, @Switch(name = 's', desc = "List sub-commands of the given command, if applicable") boolean listSubCommands, - @Arg(desc = "The page to retrieve", def = "1") + @ArgFlag(name = 'p', desc = "The page to retrieve", def = "1") int page, @Arg(desc = "The command to retrieve help for", def = "", variable = true) List command) throws WorldEditException { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java index f0de910e8..b70bad5fe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/CommandPermissionsConditionGenerator.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.command.util; import com.google.common.collect.ImmutableSet; import org.enginehub.piston.Command; import org.enginehub.piston.gen.CommandConditionGenerator; -import org.enginehub.piston.gen.CommandRegistration; import org.enginehub.piston.util.NonnullByDefault; import java.lang.reflect.Method; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java index ab21a39b9..ad7dad226 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -135,7 +135,7 @@ public class PrintCommandHelp { String used = commandList.isEmpty() ? null : toCommandString(commandList); CommandListBox box = new CommandListBox( (used == null ? "Help" : "Subcommands: " + used), - "//help -s %page%" + (used == null ? "" : " " + used)); + "//help -s -p %page%" + (used == null ? "" : " " + used)); if (!actor.isPlayer()) { box.formatForConsole(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java new file mode 100644 index 000000000..903a12449 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java @@ -0,0 +1,27 @@ +package com.sk89q.worldedit.command.util; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.formatting.text.Component; + +import javax.annotation.Nullable; +import java.util.concurrent.Callable; + +/** + * For internal WorldEdit use only. + */ +public final class WorldEditAsyncCommandBuilder { + private WorldEditAsyncCommandBuilder() { + } + + public static void createAndSendMessage(Actor actor, Callable task, @Nullable String desc) { + final AsyncCommandBuilder builder = AsyncCommandBuilder.wrap(task, actor); + if (desc != null) { + builder.sendMessageAfterDelay(desc); + } + builder + .onSuccess((String) null, actor::print) + .onFailure((String) null, WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter()) + .buildAndExec(WorldEdit.getInstance().getExecutorService()); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 8708de678..0b6c56361 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -101,7 +101,6 @@ import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; import com.sk89q.worldedit.world.World; -import org.enginehub.piston.ColorConfig; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; import org.enginehub.piston.TextConfig; @@ -477,6 +476,8 @@ public final class PlatformCommandManager { } catch (ConditionFailedException e) { if (e.getCondition() instanceof PermissionCondition) { actor.printError("You are not permitted to do that. Are you in the right mode?"); + } else { + actor.print(e.getRichMessage()); } } catch (UsageException e) { actor.print(TextComponent.builder("") @@ -487,7 +488,6 @@ public final class PlatformCommandManager { if (!cmd.isEmpty()) { actor.print(TextComponent.builder("Usage: ") .color(TextColor.RED) - .append(TextComponent.of("/", ColorConfig.getMainText())) .append(HelpGenerator.create(e.getCommandParseResult()).getUsage()) .build()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java index dec0d6e24..1a0b440cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandRegistrationHandler.java @@ -20,15 +20,12 @@ package com.sk89q.worldedit.internal.command; import com.google.common.collect.ImmutableList; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; -import com.sk89q.worldedit.internal.command.CommandLoggingHandler; import org.enginehub.piston.CommandManager; import org.enginehub.piston.gen.CommandCallListener; import org.enginehub.piston.gen.CommandRegistration; import java.util.List; -import java.util.logging.Logger; public class CommandRegistrationHandler { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java index 6654d5dec..8c8031ffd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemType.java @@ -33,6 +33,7 @@ public class ItemType implements Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("item type"); private String id; + private String name; public ItemType(String id) { // If it has no namespace, assume minecraft. @@ -53,12 +54,14 @@ public class ItemType implements Keyed { * @return The name, or ID */ public String getName() { - String name = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getItemRegistry().getName(this); if (name == null) { - return getId(); - } else { - return name; + name = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries() + .getItemRegistry().getName(this); + if (name == null) { + name = ""; + } } + return name.isEmpty() ? getId() : name; } From 1e7c074217738f24afc70377c6d8433ec0c5f77e Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 1 Jun 2019 07:41:19 -0400 Subject: [PATCH 167/366] Few misc command fixes. --- .../bukkit/BukkitCommandInspector.java | 5 +--- .../worldedit/bukkit/WorldEditListener.java | 5 +--- .../worldedit/command/GeneralCommands.java | 7 +++-- .../command/util/PermissionCondition.java | 1 - .../util/WorldEditAsyncCommandBuilder.java | 19 ++++++++++++ .../platform/PlatformCommandManager.java | 5 ++++ .../sk89q/worldedit/forge/CommandWrapper.java | 30 +++++++++---------- 7 files changed, 44 insertions(+), 28 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java index 0cd9b1b9d..005d79259 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java @@ -80,10 +80,7 @@ class BukkitCommandInspector implements CommandInspector { InjectedValueStore store = MapBackedValueStore.create(); store.injectValue(Key.of(Actor.class), context -> Optional.of(plugin.wrapCommandSender(sender))); - CommandParameters parameters = NoInputCommandParameters.builder() - .injectedValues(MemoizingValueAccess.wrap(store)) - .build(); - return mapping.get().getCondition().satisfied(parameters); + return mapping.get().getCondition().satisfied(store); } else { logger.warn("BukkitCommandInspector doesn't know how about the command '" + command + "'"); return false; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java index 69c803880..8f19dc3a0 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java @@ -77,14 +77,11 @@ public class WorldEditListener implements Listener { InjectedValueStore store = MapBackedValueStore.create(); store.injectValue(Key.of(Actor.class), context -> Optional.of(plugin.wrapCommandSender(event.getPlayer()))); - CommandParameters parameters = NoInputCommandParameters.builder() - .injectedValues(MemoizingValueAccess.wrap(store)) - .build(); CommandManager commandManager = plugin.getWorldEdit().getPlatformManager().getPlatformCommandManager().getCommandManager(); event.getCommands().removeIf(name -> // remove if in the manager and not satisfied commandManager.getCommand(name) - .filter(command -> !command.getCondition().satisfied(parameters)) + .filter(command -> !command.getCondition().satisfied(store)) .isPresent() ); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 34a56b8e5..92ab5611d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -219,15 +219,16 @@ public class GeneralCommands { aliases = {"/searchitem", "/l", "/search"}, desc = "Search for an item" ) + @CommandPermissions("worldedit.searchitem") public void searchItem(Actor actor, - @Arg(desc = "Search query", variable = true) - List query, @Switch(name = 'b', desc = "Only search for blocks") boolean blocksOnly, @Switch(name = 'i', desc = "Only search for items") boolean itemsOnly, @ArgFlag(name = 'p', desc = "Page of results to return", def = "1") - int page) { + int page, + @Arg(desc = "Search query", variable = true) + List query) { String search = String.join(" ", query); if (search.length() <= 2) { actor.printError("Enter a longer search string (len > 2)."); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java index a3ba83c6f..ac92b2fef 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.command.util; import com.sk89q.worldedit.extension.platform.Actor; import org.enginehub.piston.Command; -import org.enginehub.piston.CommandParameters; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java index 903a12449..f21fb2b6d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/WorldEditAsyncCommandBuilder.java @@ -1,3 +1,22 @@ +/* + * 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.command.util; import com.sk89q.worldedit.WorldEdit; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 0b6c56361..9d2e53d8f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -125,6 +125,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Consumer; @@ -583,6 +584,10 @@ public final class PlatformCommandManager { original.getEnd() + 1 ); }).collect(Collectors.toList())); + } catch (ConditionFailedException e) { + if (e.getCondition() instanceof PermissionCondition) { + event.setSuggestions(new ArrayList<>()); + } } catch (CommandException e) { event.getActor().printError(e.getMessage()); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java index 6a15e51dd..4c871e655 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java @@ -31,17 +31,20 @@ import com.mojang.brigadier.suggestion.Suggestion; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.util.Substring; import net.minecraft.command.CommandSource; +import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayerMP; +import org.enginehub.piston.inject.InjectedValueStore; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.inject.MapBackedValueStore; import java.util.List; -import java.util.Set; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; -import java.util.stream.Stream; import static net.minecraft.command.Commands.argument; import static net.minecraft.command.Commands.literal; @@ -58,8 +61,7 @@ public final class CommandWrapper { .then(argument("args", StringArgumentType.greedyString()) .suggests(CommandWrapper::suggest) .executes(FAKE_COMMAND)); - if (command.getCondition().as(PermissionCondition.class) - .filter(p -> p.getPermissions().size() > 0).isPresent()) { + if (command.getCondition() != org.enginehub.piston.Command.Condition.TRUE) { base.requires(requirementsFor(command)); } dispatcher.register(base); @@ -67,8 +69,7 @@ public final class CommandWrapper { } public static final Command FAKE_COMMAND = ctx -> { - EntityPlayerMP player = ctx.getSource().asPlayer(); - if (player.world.isRemote()) { + if (ctx.getSource().getWorld().isRemote) { return 0; } return 1; @@ -76,15 +77,12 @@ public final class CommandWrapper { private static Predicate requirementsFor(org.enginehub.piston.Command mapping) { return ctx -> { - ForgePermissionsProvider permsProvider = ForgeWorldEdit.inst.getPermissionsProvider(); - return ctx.getEntity() instanceof EntityPlayerMP && - mapping.getCondition().as(PermissionCondition.class) - .map(PermissionCondition::getPermissions) - .map(Set::stream) - .orElseGet(Stream::empty) - .allMatch(perm -> permsProvider.hasPermission( - (EntityPlayerMP) ctx.getEntity(), perm - )); + final Entity entity = ctx.getEntity(); + if (!(entity instanceof EntityPlayerMP)) return true; + final Actor actor = ForgeAdapter.adaptPlayer(((EntityPlayerMP) entity)); + InjectedValueStore store = MapBackedValueStore.create(); + store.injectValue(Key.of(Actor.class), context -> Optional.of(actor)); + return mapping.getCondition().satisfied(store); }; } From a3ca670a328981d0672f5762e4730c616249926a Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 1 Jun 2019 09:48:45 -0400 Subject: [PATCH 168/366] Fix sponge perms too. Untested tho cuz 1.13 lol --- .../java/com/sk89q/worldedit/sponge/CommandAdapter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java index afbb2a51c..01340ae4b 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/CommandAdapter.java @@ -44,11 +44,11 @@ public abstract class CommandAdapter implements CommandCallable { .map(PermissionCondition::getPermissions) .orElseGet(Collections::emptySet); for (String perm : permissions) { - if (!source.hasPermission(perm)) { - return false; + if (source.hasPermission(perm)) { + return true; } } - return true; + return false; } @Override From a3afd9d5b3b699c02d5ae0c3f45b96bbf21b0d90 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 1 Jun 2019 12:32:14 -0400 Subject: [PATCH 169/366] Make suggestions more robust. And fix potential errors in the ^[] pattern parser. --- .../TypeOrStateApplyingPatternParser.java | 21 ++++++++++++++----- .../platform/PlatformCommandManager.java | 13 +++++++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java index 8897b115a..5b368e644 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/TypeOrStateApplyingPatternParser.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.extension.factory.parser.pattern; -import com.google.common.base.Splitter; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.extension.input.InputParseException; @@ -32,6 +31,7 @@ import com.sk89q.worldedit.function.pattern.StateApplyingPattern; import com.sk89q.worldedit.function.pattern.TypeApplyingPattern; import com.sk89q.worldedit.internal.registry.InputParser; +import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; @@ -82,10 +82,21 @@ public class TypeOrStateApplyingPatternParser extends InputParser { worldEdit.getBlockFactory().parseFromInput(type, context).getBlockType().getDefaultState()); } else { // states given - if (!parts[1].endsWith("]")) throw new InputParseException("Invalid state format."); - Map statesToSet = Splitter.on(',') - .omitEmptyStrings().trimResults().withKeyValueSeparator('=') - .split(parts[1].substring(0, parts[1].length() - 1)); + if (!parts[1].endsWith("]")) throw new InputParseException("State is missing trailing ']'"); + final String[] states = parts[1].substring(0, parts[1].length() - 1).split(","); + Map statesToSet = new HashMap<>(); + for (String state : states) { + if (state.isEmpty()) throw new InputParseException("Empty part in state"); + String[] propVal = state.split("=", 2); + if (propVal.length != 2) throw new InputParseException("Missing '=' separator"); + final String prop = propVal[0]; + if (prop.isEmpty()) throw new InputParseException("Empty property in state"); + final String value = propVal[1]; + if (value.isEmpty()) throw new InputParseException("Empty value in state"); + if (statesToSet.put(prop, value) != null) { + throw new InputParseException("Duplicate properties in state"); + } + } if (type.isEmpty()) { return new StateApplyingPattern(extent, statesToSet); } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 9d2e53d8f..87d39d80b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -569,7 +569,16 @@ public final class PlatformCommandManager { .map(Substring::getSubstring) .collect(Collectors.toList()); MemoizingValueAccess access = initializeInjectedValues(() -> arguments, event.getActor()); - ImmutableSet suggestions = commandManager.getSuggestions(access, argStrings); + ImmutableSet suggestions; + try { + suggestions = commandManager.getSuggestions(access, argStrings); + } catch (Throwable t) { // catch errors which are *not* command exceptions generated by parsers/suggesters + if (!(t instanceof CommandException)) { + log.debug("Unexpected error occurred while generating suggestions for input: " + arguments, t); + return; + } + throw t; + } event.setSuggestions(suggestions.stream() .map(suggestion -> { @@ -588,8 +597,6 @@ public final class PlatformCommandManager { if (e.getCondition() instanceof PermissionCondition) { event.setSuggestions(new ArrayList<>()); } - } catch (CommandException e) { - event.getActor().printError(e.getMessage()); } } From 3a6b3dc75ca7dcb4273053c3ea817807464c9546 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 2 Jun 2019 21:50:07 -0400 Subject: [PATCH 170/366] Fix restore for 1.14 chunk format. Top-most chunk can now have lighting without have a palette or blocks. --- .../worldedit/world/chunk/AnvilChunk13.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java index 832fbf020..5cf07bd91 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -83,18 +83,17 @@ public class AnvilChunk13 implements Chunk { continue; } - int blocksPerChunkSection = 16 * 16 * 16; - BlockState[] chunkSectionBlocks = new BlockState[blocksPerChunkSection]; - blocks[y] = chunkSectionBlocks; - // parse palette List paletteEntries = sectionTag.getList("Palette", CompoundTag.class); int paletteSize = paletteEntries.size(); + if (paletteSize == 0) { + continue; + } BlockState[] palette = new BlockState[paletteSize]; for (int paletteEntryId = 0; paletteEntryId < paletteSize; paletteEntryId++) { CompoundTag paletteEntry = paletteEntries.get(paletteEntryId); BlockType type = BlockTypes.get(paletteEntry.getString("Name")); - if(type == null) { + if (type == null) { throw new InvalidFormatException("Invalid block type: " + paletteEntry.getString("Name")); } BlockState blockState = type.getDefaultState(); @@ -121,11 +120,16 @@ public class AnvilChunk13 implements Chunk { // parse block states long[] blockStatesSerialized = NBTUtils.getChildTag(sectionTag.getValue(), "BlockStates", LongArrayTag.class).getValue(); + + int blocksPerChunkSection = 16 * 16 * 16; + BlockState[] chunkSectionBlocks = new BlockState[blocksPerChunkSection]; + blocks[y] = chunkSectionBlocks; + long currentSerializedValue = 0; int nextSerializedItem = 0; int remainingBits = 0; for (int blockPos = 0; blockPos < blocksPerChunkSection; blockPos++) { - int localBlockId = 0; + int localBlockId; if (remainingBits < paletteBits) { int bitsNextLong = paletteBits - remainingBits; localBlockId = (int) currentSerializedValue; From 3df2410254ed9d3598b4e2d8e76a57cb89bb5791 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 2 Jun 2019 21:50:41 -0400 Subject: [PATCH 171/366] Change chunk loading method. Behavior of loadChunk changed a lot for the worse in CB 1.14. --- .../src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 0eb37223e..67d643f89 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 @@ -305,9 +305,7 @@ public class BukkitWorld extends AbstractWorld { public void checkLoadedChunk(BlockVector3 pt) { World world = getWorld(); - if (!world.isChunkLoaded(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)) { - world.loadChunk(pt.getBlockX() >> 4, pt.getBlockZ() >> 4); - } + world.getChunkAt(pt.getBlockX() >> 4, pt.getBlockZ() >> 4); } @Override From e3097dd0fca635eb8a572366766a46eb3f6a753f Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 3 Jun 2019 23:56:34 -0400 Subject: [PATCH 172/366] Use java-library to exclude some deps. --- worldedit-bukkit/build.gradle | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 17cdc5f6e..28dc522c6 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'maven' +apply plugin: 'java-library' repositories { maven { url "https://hub.spigotmc.org/nexus/content/groups/public" } @@ -15,14 +16,14 @@ configurations.all { Configuration it -> } dependencies { - compile project(':worldedit-core') - compile project(':worldedit-libs:bukkit') - compile 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz + api project(':worldedit-core') + api project(':worldedit-libs:bukkit') + api 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz compileOnly 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' - compile 'io.papermc:paperlib:1.0.2' + implementation 'io.papermc:paperlib:1.0.2' compileOnly 'com.sk89q:dummypermscompat:1.10' - compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' - compile 'org.bstats:bstats-bukkit:1.4' + implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' + implementation 'org.bstats:bstats-bukkit:1.4' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } From 2ef7cfd038466356b547e1286b446de908534d8b Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 4 Jun 2019 18:31:19 -0400 Subject: [PATCH 173/366] Update readme links. --- README.md | 10 +++++----- gradle.properties | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6d9968e37..93290bcf6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ WorldEdit is Minecraft mod that turns Minecraft into an in-game map editor (sorta, kinda). -* Make awesome stuff with half the time OR make ***quadriply** awesome* creations with the same time :sparkles: +* Make awesome stuff with half the time OR make ***quadruply** awesome* creations with the same time :sparkles: * Get lost in hundreds of options and functions that even we've forgotten existed * Utilize Photoshop-like tools like "selection areas" and "brushes" * Making fjords and other natural wonders with weird names @@ -28,8 +28,8 @@ Links ----- * [Visit our website](http://www.enginehub.org/) -* [Discord](https://discord.gg/wvneRVm) -* [IRC channel](http://skq.me/irc/irc.esper.net/sk89q/) (#sk89q on irc.esper.net) -* [Issue tracker](http://youtrack.sk89q.com/issues/WORLDEDIT) +* [Discord](https://discord.gg/enginehub) +* [IRC channel](https://webchat.esper.net/?join=sk89q) (#sk89q on irc.esper.net) +* [Issue tracker](https://dev.enginehub.org/youtrack/issues/WORLDEDIT) * [Continuous integration](http://builds.enginehub.org) [![Build Status](https://travis-ci.org/EngineHub/WorldEdit.svg?branch=master)](https://travis-ci.org/EngineHub/WorldEdit) -* [End-user documentation](http://wiki.sk89q.com/wiki/WorldEdit) +* [End-user documentation](https://worldedit.readthedocs.io/en/latest/) / [Older Wiki](http://wiki.sk89q.com/wiki/WorldEdit) diff --git a/gradle.properties b/gradle.properties index 878bf1f7e..d210d4f53 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. -org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false \ No newline at end of file +#org.gradle.jvmargs=-Xmx3G +#org.gradle.daemon=false \ No newline at end of file From bae2a0b244f00e7b2a97972ab4e73d95958ffc69 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 4 Jun 2019 18:57:40 -0700 Subject: [PATCH 174/366] Update Piston to 0.4.1 for bugfixes --- worldedit-libs/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 4f07f5aae..76bd162f9 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -91,7 +91,7 @@ configure(subprojects + project("core:ap")) { def textExtrasVersion = "3.0.2" project("core") { def textVersion = "3.0.1" - def pistonVersion = '0.4.0' + def pistonVersion = '0.4.1' dependencies { shade "net.kyori:text-api:$textVersion" From a904ff9fb9acbbd6dfc067628cf095877f5454a5 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 1 Jun 2019 09:16:08 -0400 Subject: [PATCH 175/366] Check sub-command permissions. This ensures root commands aren't sent to the client/suggested unless a player has at least one subcommand available to them. --- .../command/util/PermissionCondition.java | 2 +- .../util/SubCommandPermissionCondition.java | 52 +++++++++++++++++++ .../platform/PlatformCommandManager.java | 6 ++- 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java index ac92b2fef..6f6de7a0d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java @@ -26,7 +26,7 @@ import org.enginehub.piston.inject.Key; import java.util.Set; -public final class PermissionCondition implements Command.Condition { +public class PermissionCondition implements Command.Condition { private static final Key ACTOR_KEY = Key.of(Actor.class); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java new file mode 100644 index 000000000..12170980e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java @@ -0,0 +1,52 @@ +/* + * 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.command.util; + +import org.enginehub.piston.Command; +import org.enginehub.piston.inject.InjectedValueAccess; + +import java.util.Collection; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class SubCommandPermissionCondition extends PermissionCondition { + + private final Command.Condition aggregate; + + public SubCommandPermissionCondition(Collection commands) { + super(commands.stream().map(Command::getCondition) + .map(c -> c.as(PermissionCondition.class)) + .flatMap(optCon -> optCon.map(permCon -> permCon.getPermissions().stream()).orElse(Stream.empty())) + .collect(Collectors.toSet())); + this.aggregate = commands.stream().map(Command::getCondition) + .map(c -> c.as(PermissionCondition.class)) + .filter(Optional::isPresent) + .map(Optional::get) + .map(c -> c.as(Command.Condition.class)) + .map(Optional::get) + .reduce(Command.Condition::or).orElse(Command.Condition.TRUE); + } + + @Override + public boolean satisfied(InjectedValueAccess context) { + return aggregate.satisfied(context); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 87d39d80b..c74f46367 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -80,6 +80,7 @@ import com.sk89q.worldedit.command.argument.RegistryConverter; import com.sk89q.worldedit.command.argument.VectorConverter; import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter; import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.command.util.SubCommandPermissionCondition; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.CommandEvent; @@ -266,11 +267,14 @@ public final class PlatformCommandManager { ); additionalConfig.accept(manager); + final List subCommands = manager.getAllCommands().collect(Collectors.toList()); cmd.addPart(SubCommandPart.builder(TranslatableComponent.of("worldedit.argument.action"), TextComponent.of("Sub-command to run.")) - .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .withCommands(subCommands) .required() .build()); + + cmd.condition(new SubCommandPermissionCondition(subCommands)); }); } From d7c11cbb690fada46d14f34ec5cb9231ff03d2ed Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 2 Jun 2019 02:11:36 -0400 Subject: [PATCH 176/366] Handle sub-commands without permissions. --- .../command/util/PermissionCondition.java | 3 +- .../util/SubCommandPermissionCondition.java | 45 ++++++++++++------- .../platform/PlatformCommandManager.java | 2 +- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java index 6f6de7a0d..99a4622d6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PermissionCondition.java @@ -42,7 +42,8 @@ public class PermissionCondition implements Command.Condition { @Override public boolean satisfied(InjectedValueAccess context) { - return context.injectedValue(ACTOR_KEY) + return permissions.isEmpty() || + context.injectedValue(ACTOR_KEY) .map(actor -> permissions.stream().anyMatch(actor::hasPermission)) .orElse(false); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java index 12170980e..c501bbbeb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SubCommandPermissionCondition.java @@ -19,34 +19,49 @@ package com.sk89q.worldedit.command.util; +import com.google.common.collect.ImmutableSet; import org.enginehub.piston.Command; import org.enginehub.piston.inject.InjectedValueAccess; -import java.util.Collection; +import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; -public class SubCommandPermissionCondition extends PermissionCondition { +public final class SubCommandPermissionCondition extends PermissionCondition { private final Command.Condition aggregate; - public SubCommandPermissionCondition(Collection commands) { - super(commands.stream().map(Command::getCondition) - .map(c -> c.as(PermissionCondition.class)) - .flatMap(optCon -> optCon.map(permCon -> permCon.getPermissions().stream()).orElse(Stream.empty())) - .collect(Collectors.toSet())); - this.aggregate = commands.stream().map(Command::getCondition) - .map(c -> c.as(PermissionCondition.class)) - .filter(Optional::isPresent) - .map(Optional::get) - .map(c -> c.as(Command.Condition.class)) - .map(Optional::get) - .reduce(Command.Condition::or).orElse(Command.Condition.TRUE); + private SubCommandPermissionCondition(Set perms, Command.Condition aggregate) { + super(perms); + this.aggregate = aggregate; } @Override public boolean satisfied(InjectedValueAccess context) { return aggregate.satisfied(context); } + + public static class Generator { + private final List subCommands; + + public Generator(List subCommands) { + this.subCommands = subCommands; + } + + public Command.Condition build() { + final List conditions = subCommands.stream().map(Command::getCondition).collect(Collectors.toList()); + final List> permConds = conditions.stream().map(c -> c.as(PermissionCondition.class)).collect(Collectors.toList()); + if (permConds.stream().anyMatch(o -> !o.isPresent())) { + // if any sub-command doesn't require permissions, then this command doesn't require permissions + return new PermissionCondition(ImmutableSet.of()); + } + // otherwise, this command requires any one subcommand to be available + final Set perms = permConds.stream().map(Optional::get).flatMap(cond -> cond.getPermissions().stream()).collect(Collectors.toSet()); + final Command.Condition aggregate = permConds.stream().map(Optional::get) + .map(c -> (Command.Condition) c) + .reduce(Command.Condition::or).orElse(TRUE); + return new SubCommandPermissionCondition(perms, aggregate); + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index c74f46367..2de667d08 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -274,7 +274,7 @@ public final class PlatformCommandManager { .required() .build()); - cmd.condition(new SubCommandPermissionCondition(subCommands)); + cmd.condition(new SubCommandPermissionCondition.Generator(subCommands).build()); }); } From 5c2ed0228d34eccb34453ca1c8a74301e8bbf45c Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Wed, 5 Jun 2019 22:01:57 +1000 Subject: [PATCH 177/366] Update to RC3 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 839562495..aea7c30a4 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ println """ allprojects { group = 'com.sk89q.worldedit' - version = '7.0.0-SNAPSHOT' + version = '7.0.0-rc-3' } if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost" From 1b4ea528ea4ab789228a1913ab70b1d73a732ff3 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Wed, 5 Jun 2019 22:02:08 +1000 Subject: [PATCH 178/366] Back to SNAPSHOT for continued development --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index aea7c30a4..839562495 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ println """ allprojects { group = 'com.sk89q.worldedit' - version = '7.0.0-rc-3' + version = '7.0.0-SNAPSHOT' } if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost" From dc380b1fb38bbe128dc1d530fcaeb6cb1d97ef46 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 2 Jun 2019 23:39:01 -0400 Subject: [PATCH 179/366] Ugly but working generator for rst commands. --- .../internal/util/DocumentationPrinter.java | 205 ++++-------------- 1 file changed, 44 insertions(+), 161 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java index 4728bc9b8..a42e7a2a3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java @@ -19,34 +19,21 @@ package com.sk89q.worldedit.internal.util; -import com.sk89q.minecraft.util.commands.Command; -import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.minecraft.util.commands.NestedCommand; -import com.sk89q.worldedit.command.BiomeCommands; -import com.sk89q.worldedit.command.ChunkCommands; -import com.sk89q.worldedit.command.ClipboardCommands; -import com.sk89q.worldedit.command.GeneralCommands; -import com.sk89q.worldedit.command.GenerationCommands; -import com.sk89q.worldedit.command.HistoryCommands; -import com.sk89q.worldedit.command.NavigationCommands; -import com.sk89q.worldedit.command.RegionCommands; -import com.sk89q.worldedit.command.ScriptingCommands; -import com.sk89q.worldedit.command.SelectionCommands; -import com.sk89q.worldedit.command.SnapshotUtilCommands; -import com.sk89q.worldedit.command.ToolCommands; -import com.sk89q.worldedit.command.ToolUtilCommands; -import com.sk89q.worldedit.command.UtilityCommands; +import com.google.common.base.Strings; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.extension.platform.PlatformCommandManager; +import com.sk89q.worldedit.extension.platform.PlatformManager; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.TextConfig; +import org.enginehub.piston.part.SubCommandPart; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.stream.Stream; -@SuppressWarnings("UseOfSystemOutOrSystemErr") public final class DocumentationPrinter { private DocumentationPrinter() { @@ -56,153 +43,49 @@ public final class DocumentationPrinter { * Generates documentation. * * @param args arguments - * @throws IOException thrown on I/O error */ - public static void main(String[] args) throws IOException { - File commandsDir = new File(args[0]); - - List> commandClasses = getCommandClasses(commandsDir); - - System.out.println("Writing permissions wiki table..."); - writePermissionsWikiTable(commandClasses); - System.out.println("Writing Bukkit plugin.yml..."); - writeBukkitYAML(); - - System.out.println("Done!"); + public static void main(String[] args) { + final PlatformManager platformManager = WorldEdit.getInstance().getPlatformManager(); + PlatformCommandManager mgr = platformManager.getPlatformCommandManager(); + final CommandManager commandManager = mgr.getCommandManager(); + dumpCommands(commandManager); } - private static List> getCommandClasses(File dir) { - List> classes = new ArrayList<>(); + private static void dumpCommands(CommandManager commandManager) { + final PlainComponentSerializer serializer = new PlainComponentSerializer(kbc -> "", TranslatableComponent::key); + cmdToUsages(serializer, commandManager.getAllCommands(), TextConfig.getCommandPrefix(), 0); - classes.add(BiomeCommands.class); - classes.add(ChunkCommands.class); - classes.add(ClipboardCommands.class); - classes.add(GeneralCommands.class); - classes.add(GenerationCommands.class); - classes.add(HistoryCommands.class); - classes.add(NavigationCommands.class); - classes.add(RegionCommands.class); - classes.add(ScriptingCommands.class); - classes.add(SelectionCommands.class); - classes.add(SnapshotUtilCommands.class); - classes.add(ToolUtilCommands.class); - classes.add(ToolCommands.class); - classes.add(UtilityCommands.class); - - /*for (File f : dir.listFiles()) { - if (!f.getName().matches("^.*\\.java$")) { - continue; - } - - String className = "com.sk89q.worldedit.commands." - + f.getName().substring(0, f.getName().lastIndexOf(".")); - - Class cls; - try { - cls = Class.forName(className, true, - Thread.currentThread().getContextClassLoader()); - } catch (ClassNotFoundException e) { - continue; - } - - classes.add(cls); - }*/ - - return classes; + cmdsToPerms(commandManager.getAllCommands(), TextConfig.getCommandPrefix()); } - private static void writePermissionsWikiTable(List> commandClasses) - throws IOException { - try (FileOutputStream stream = new FileOutputStream("wiki_permissions.txt")) { - PrintStream print = new PrintStream(stream); - writePermissionsWikiTable(print, commandClasses, "/"); - } + private static void cmdsToPerms(Stream cmds, String prefix) { + cmds.forEach(c -> { + System.out.println(" " + cmdToPerm(prefix, c)); + c.getParts().stream().filter(p -> p instanceof SubCommandPart).map(p -> (SubCommandPart) p) + .forEach(scp -> cmdsToPerms(scp.getCommands().stream(), prefix + c.getName() + " ")); + }); } - private static void writePermissionsWikiTable(PrintStream stream, - List> commandClasses, String prefix) { - - for (Class cls : commandClasses) { - for (Method method : cls.getMethods()) { - if (!method.isAnnotationPresent(Command.class)) { - continue; - } - - Command cmd = method.getAnnotation(Command.class); - - stream.println("|-"); - stream.print("| " + prefix + cmd.aliases()[0]); - stream.print(" || "); - - if (method.isAnnotationPresent(CommandPermissions.class)) { - CommandPermissions perms = - method.getAnnotation(CommandPermissions.class); - - String[] permKeys = perms.value(); - for (int i = 0; i < permKeys.length; ++i) { - if (i > 0) { - stream.print(", "); - } - stream.print(permKeys[i]); - } - } - - stream.print(" || "); - - boolean firstAlias = true; - if (cmd.aliases().length != 0) { - for (String alias : cmd.aliases()) { - if (!firstAlias) stream.print("
    "); - stream.print(prefix + alias); - firstAlias = false; - } - } - - stream.print(" || "); - - if (cmd.flags() != null && !cmd.flags().isEmpty()) { - stream.print(cmd.flags()); - } - - stream.print(" || "); - - if (cmd.desc() != null && !cmd.desc().isEmpty()) { - stream.print(cmd.desc()); - } - - stream.println(); - - if (method.isAnnotationPresent(NestedCommand.class)) { - NestedCommand nested = - method.getAnnotation(NestedCommand.class); - - Class[] nestedClasses = nested.value(); - writePermissionsWikiTable(stream, - Arrays.asList(nestedClasses), - prefix + cmd.aliases()[0] + " "); - } - } - } + private static String cmdToPerm(String prefix, Command c) { + return prefix + c.getName() + ",\"" + (c.getCondition() instanceof PermissionCondition + ? String.join(", ", ((PermissionCondition) c.getCondition()).getPermissions()) : "") + "\""; } - private static void writeBukkitYAML() - throws IOException { - try (FileOutputStream stream = new FileOutputStream("plugin.yml")) { - PrintStream print = new PrintStream(stream); - writeBukkitYAML(print); - } + private static void cmdToUsages(PlainComponentSerializer serializer, Stream cmds, String prefix, int indent) { + cmds.forEach(c -> { + System.out.println(Strings.repeat("\t", indent) + cmdToString(serializer, prefix, c, indent)); + c.getParts().stream().filter(p -> p instanceof SubCommandPart).map(p -> (SubCommandPart) p) + .forEach(scp -> cmdToUsages(serializer, scp.getCommands().stream(), prefix + c.getName() + " ", indent + 1)); + System.out.println(); + }); } - private static void writeBukkitYAML(PrintStream stream) { - stream.println("name: WorldEdit"); - stream.println("main: com.sk89q.worldedit.bukkit.WorldEditPlugin"); - stream.println("version: ${project.version}"); - stream.println("softdepend: [Spout] #hack to fix trove errors"); - - stream.println(); - stream.println(); - stream.println("# Permissions aren't here. Read http://wiki.sk89q.com/wiki/WEPIF/DinnerPerms"); - stream.println("# for how WorldEdit permissions actually work."); + private static String cmdToString(PlainComponentSerializer serializer, String prefix, Command c, int indent) { + return serializer.serialize(TextComponent.of(prefix + c.getName()).append(TextComponent.newline()) + .append(TextComponent.of(c.getCondition() instanceof PermissionCondition + ? "Permissions: " + (String.join(", ", ((PermissionCondition) c.getCondition()).getPermissions())) + "\n" + : "")) + .append(c.getFullHelp())).replace("\n", "\n" + Strings.repeat("\t", indent)); } } From 34020f7bd26dcd2d3a952c7b02e9c401d3414d9c Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 5 Jun 2019 10:23:41 -0400 Subject: [PATCH 180/366] Less ugly. Makes tables for all commands and subcommands. --- .../internal/util/DocumentationPrinter.java | 384 ++++++++++++++++-- 1 file changed, 350 insertions(+), 34 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java index a42e7a2a3..8c2bdb46f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java @@ -20,72 +20,388 @@ package com.sk89q.worldedit.internal.util; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.io.Files; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.ApplyBrushCommands; +import com.sk89q.worldedit.command.BiomeCommands; +import com.sk89q.worldedit.command.BiomeCommandsRegistration; +import com.sk89q.worldedit.command.BrushCommands; +import com.sk89q.worldedit.command.BrushCommandsRegistration; +import com.sk89q.worldedit.command.ChunkCommands; +import com.sk89q.worldedit.command.ChunkCommandsRegistration; +import com.sk89q.worldedit.command.ClipboardCommands; +import com.sk89q.worldedit.command.ClipboardCommandsRegistration; +import com.sk89q.worldedit.command.ExpandCommands; +import com.sk89q.worldedit.command.GeneralCommands; +import com.sk89q.worldedit.command.GeneralCommandsRegistration; +import com.sk89q.worldedit.command.GenerationCommands; +import com.sk89q.worldedit.command.GenerationCommandsRegistration; +import com.sk89q.worldedit.command.HistoryCommands; +import com.sk89q.worldedit.command.HistoryCommandsRegistration; +import com.sk89q.worldedit.command.NavigationCommands; +import com.sk89q.worldedit.command.NavigationCommandsRegistration; +import com.sk89q.worldedit.command.PaintBrushCommands; +import com.sk89q.worldedit.command.RegionCommands; +import com.sk89q.worldedit.command.RegionCommandsRegistration; +import com.sk89q.worldedit.command.SchematicCommands; +import com.sk89q.worldedit.command.SchematicCommandsRegistration; +import com.sk89q.worldedit.command.ScriptingCommands; +import com.sk89q.worldedit.command.ScriptingCommandsRegistration; +import com.sk89q.worldedit.command.SelectionCommands; +import com.sk89q.worldedit.command.SelectionCommandsRegistration; +import com.sk89q.worldedit.command.SnapshotCommands; +import com.sk89q.worldedit.command.SnapshotCommandsRegistration; +import com.sk89q.worldedit.command.SnapshotUtilCommands; +import com.sk89q.worldedit.command.SnapshotUtilCommandsRegistration; +import com.sk89q.worldedit.command.SuperPickaxeCommands; +import com.sk89q.worldedit.command.SuperPickaxeCommandsRegistration; +import com.sk89q.worldedit.command.ToolCommands; +import com.sk89q.worldedit.command.ToolCommandsRegistration; +import com.sk89q.worldedit.command.ToolUtilCommands; +import com.sk89q.worldedit.command.ToolUtilCommandsRegistration; +import com.sk89q.worldedit.command.UtilityCommands; +import com.sk89q.worldedit.command.UtilityCommandsRegistration; +import com.sk89q.worldedit.command.WorldEditCommands; +import com.sk89q.worldedit.command.WorldEditCommandsRegistration; import com.sk89q.worldedit.command.util.PermissionCondition; -import com.sk89q.worldedit.extension.platform.PlatformCommandManager; -import com.sk89q.worldedit.extension.platform.PlatformManager; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.formatting.text.serializer.ComponentSerializer; import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; import org.enginehub.piston.TextConfig; +import org.enginehub.piston.gen.CommandRegistration; +import org.enginehub.piston.impl.CommandManagerImpl; +import org.enginehub.piston.impl.CommandManagerServiceImpl; import org.enginehub.piston.part.SubCommandPart; +import org.enginehub.piston.util.HelpGenerator; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; import java.util.stream.Stream; public final class DocumentationPrinter { - private DocumentationPrinter() { - } - /** * Generates documentation. * * @param args arguments */ - public static void main(String[] args) { - final PlatformManager platformManager = WorldEdit.getInstance().getPlatformManager(); - PlatformCommandManager mgr = platformManager.getPlatformCommandManager(); - final CommandManager commandManager = mgr.getCommandManager(); - dumpCommands(commandManager); + public static void main(String[] args) throws IOException { + final DocumentationPrinter printer = new DocumentationPrinter(); + + printer.writeAllCommands(); + writeOutput("commands.rst", printer.cmdOutput.toString()); + writeOutput("permissions.rst", printer.permsOutput.toString()); } - private static void dumpCommands(CommandManager commandManager) { - final PlainComponentSerializer serializer = new PlainComponentSerializer(kbc -> "", TranslatableComponent::key); - cmdToUsages(serializer, commandManager.getAllCommands(), TextConfig.getCommandPrefix(), 0); - - cmdsToPerms(commandManager.getAllCommands(), TextConfig.getCommandPrefix()); + private static void writeOutput(String file, String output) throws IOException { + File outfile = new File(file); + Files.write(output, outfile, StandardCharsets.UTF_8); } - private static void cmdsToPerms(Stream cmds, String prefix) { + private final ComponentSerializer serializer + = new PlainComponentSerializer(kb -> "", TranslatableComponent::key); + private final CommandRegistrationHandler registration; + private final CommandManagerServiceImpl commandManagerService; + private final WorldEdit worldEdit = WorldEdit.getInstance(); + private StringBuilder cmdOutput; + private StringBuilder permsOutput; + private Field mgrCmdField; + + private DocumentationPrinter() { + this.cmdOutput = new StringBuilder(); + this.permsOutput = new StringBuilder(); + this.registration = new CommandRegistrationHandler(ImmutableList.of()); + this.commandManagerService = new CommandManagerServiceImpl(); + try { + Field field = CommandManagerImpl.class.getDeclaredField("commands"); + field.setAccessible(true); + this.mgrCmdField = field; + } catch (NoSuchFieldException ignored) { + } + } + + private void registerSubCommands(CommandManager parent, String name, List aliases, String desc, + CommandRegistration registration, CI instance) { + registerSubCommands(parent, name, aliases, desc, registration, instance, m -> {}); + } + + private void registerSubCommands(CommandManager parent, String name, List aliases, String desc, + CommandRegistration registration, CI instance, + Consumer additionalConfig) { + parent.register(name, cmd -> { + cmd.aliases(aliases); + cmd.description(TextComponent.of(desc)); + cmd.action(Command.Action.NULL_ACTION); + + CommandManager manager = createManager(); + this.registration.register( + manager, + registration, + instance + ); + additionalConfig.accept(manager); + + cmd.addPart(SubCommandPart.builder(TranslatableComponent.of("worldedit.argument.action"), + TextComponent.of("Sub-command to run.")) + .withCommands(manager.getAllCommands().collect(Collectors.toList())) + .required() + .build()); + }); + } + + private void writeAllCommands() { + writeHeader(); + + CommandManager manager; + + manager = createManager(); + registerSubCommands( + manager, + "worldedit", + ImmutableList.of("we"), + "WorldEdit commands", + WorldEditCommandsRegistration.builder(), + new WorldEditCommands(worldEdit) + ); + this.registration.register( + manager, + HistoryCommandsRegistration.builder(), + new HistoryCommands(worldEdit) + ); + this.registration.register( + manager, + GeneralCommandsRegistration.builder(), + new GeneralCommands(worldEdit) + ); + dumpSection("General Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + NavigationCommandsRegistration.builder(), + new NavigationCommands(worldEdit) + ); + dumpSection("Navigation Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + SelectionCommandsRegistration.builder(), + new SelectionCommands(worldEdit) + ); + ExpandCommands.register(registration, manager, commandManagerService); + dumpSection("Selection Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + RegionCommandsRegistration.builder(), + new RegionCommands() + ); + dumpSection("Region Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + GenerationCommandsRegistration.builder(), + new GenerationCommands(worldEdit) + ); + dumpSection("Generation Commands", manager); + + manager = createManager(); + registerSubCommands( + manager, + "schematic", + ImmutableList.of("schem", "/schematic", "/schem"), + "Schematic commands for saving/loading areas", + SchematicCommandsRegistration.builder(), + new SchematicCommands(worldEdit) + ); + this.registration.register( + manager, + ClipboardCommandsRegistration.builder(), + new ClipboardCommands() + ); + dumpSection("Schematic and Clipboard Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + ToolCommandsRegistration.builder(), + new ToolCommands(worldEdit) + ); + this.registration.register( + manager, + ToolUtilCommandsRegistration.builder(), + new ToolUtilCommands(worldEdit) + ); + dumpSection("Tool Commands", manager); + + manager = createManager(); + registerSubCommands( + manager, + "superpickaxe", + ImmutableList.of("pickaxe", "sp"), + "Super-pickaxe commands", + SuperPickaxeCommandsRegistration.builder(), + new SuperPickaxeCommands(worldEdit) + ); + dumpSection("Super Pickaxe Commands", manager); + + manager = createManager(); + registerSubCommands( + manager, + "brush", + ImmutableList.of("br", "/brush", "/br"), + "Brushing commands", + BrushCommandsRegistration.builder(), + new BrushCommands(worldEdit), + mgr -> { + PaintBrushCommands.register(commandManagerService, mgr, registration); + ApplyBrushCommands.register(commandManagerService, mgr, registration); + } + ); + dumpSection("Brush Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + BiomeCommandsRegistration.builder(), + new BiomeCommands() + ); + dumpSection("Biome Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + ChunkCommandsRegistration.builder(), + new ChunkCommands(worldEdit) + ); + dumpSection("Chunk Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + SnapshotUtilCommandsRegistration.builder(), + new SnapshotUtilCommands(worldEdit) + ); + registerSubCommands( + manager, + "snapshot", + ImmutableList.of("snap"), + "Snapshot commands for restoring backups", + SnapshotCommandsRegistration.builder(), + new SnapshotCommands(worldEdit) + ); + dumpSection("Snapshot Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + ScriptingCommandsRegistration.builder(), + new ScriptingCommands(worldEdit) + ); + dumpSection("Scripting Commands", manager); + + manager = createManager(); + this.registration.register( + manager, + UtilityCommandsRegistration.builder(), + new UtilityCommands(worldEdit) + ); + dumpSection("Utility Commands", manager); + } + + private void writeHeader() { + cmdOutput.append( + "========\n" + + "Commands\n" + + "========\n" + + "\n" + + ".. contents::\n" + + " :local:\n" + + "\n" + + ".. tip::\n" + + "\n" + + " Arguments enclosed in ``[ ]`` are optional, those enclosed in ``< >`` are required.\n\n"); + } + + private CommandManager createManager() { + final CommandManager commandManager = commandManagerService.newCommandManager(); + if (mgrCmdField != null && commandManager instanceof CommandManagerImpl) { + try { + mgrCmdField.set(commandManager, new LinkedHashMap<>()); + } catch (IllegalAccessException ignored) { + } + } + return commandManager; + } + + private void dumpSection(String title, CommandManager manager) { + cmdOutput.append(title).append("\n").append(Strings.repeat("~", title.length())).append("\n\n"); + + String prefix = TextConfig.getCommandPrefix(); + +// permsOutput.append("\n------------\n\n"); + cmdsToPerms(manager.getAllCommands(), prefix); + + for (Command command : manager.getAllCommands().collect(Collectors.toList())) { + cmdOutput.append("\n------------\n\n"); + writeCommandBlock(command, prefix, Stream.empty()); + command.getParts().stream().filter(p -> p instanceof SubCommandPart) + .flatMap(p -> ((SubCommandPart) p).getCommands().stream()) + .forEach(sc -> { + cmdOutput.append("\n------------\n\n"); + writeCommandBlock(sc, prefix + command.getName() + " ", Stream.of(command)); + }); + } + } + + private void cmdsToPerms(Stream cmds, String prefix) { cmds.forEach(c -> { - System.out.println(" " + cmdToPerm(prefix, c)); + permsOutput.append(" ").append(cmdToPerm(prefix, c)).append("\n"); c.getParts().stream().filter(p -> p instanceof SubCommandPart).map(p -> (SubCommandPart) p) .forEach(scp -> cmdsToPerms(scp.getCommands().stream(), prefix + c.getName() + " ")); }); } - private static String cmdToPerm(String prefix, Command c) { + private String cmdToPerm(String prefix, Command c) { return prefix + c.getName() + ",\"" + (c.getCondition() instanceof PermissionCondition ? String.join(", ", ((PermissionCondition) c.getCondition()).getPermissions()) : "") + "\""; } - private static void cmdToUsages(PlainComponentSerializer serializer, Stream cmds, String prefix, int indent) { - cmds.forEach(c -> { - System.out.println(Strings.repeat("\t", indent) + cmdToString(serializer, prefix, c, indent)); - c.getParts().stream().filter(p -> p instanceof SubCommandPart).map(p -> (SubCommandPart) p) - .forEach(scp -> cmdToUsages(serializer, scp.getCommands().stream(), prefix + c.getName() + " ", indent + 1)); - System.out.println(); - }); + private void writeCommandBlock(Command command, String prefix, Stream parents) { + String name = prefix + command.getName(); + String desc = serializer.serialize(command.getDescription()); + cmdOutput.append(".. csv-table::\n :widths: 8, 15\n\n"); + cmdOutput.append(" ").append(name).append(",\"").append(desc).append("\"\n"); + if (!command.getAliases().isEmpty()) { + cmdOutput.append(" Aliases,\"").append(String.join(", ", + command.getAliases().stream().map(a -> prefix + a).collect(Collectors.toSet()))) + .append("\"\n"); + } + if (command.getCondition() instanceof PermissionCondition) { + cmdOutput.append(" Permissions,\"").append(String.join(", ", ((PermissionCondition) command.getCondition()).getPermissions())).append("\"\n"); + } + cmdOutput.append(" Usage,\"").append(serializer.serialize( + HelpGenerator.create(Stream.concat(parents, Stream.of(command)).collect(Collectors.toList())).getUsage())).append("\"\n"); + command.getParts().stream().filter(part -> !(part instanceof SubCommandPart)).forEach(part -> + cmdOutput.append(" \u2001\u2001").append(serializer.serialize(part.getTextRepresentation())).append(",\"") + .append(serializer.serialize(part.getDescription())).append("\"\n")); + if (command.getFooter().isPresent()) { + cmdOutput.append(" ,\"").append(serializer.serialize(command.getFooter().get()).replace("\n", " ")).append("\"\n"); + } } - - private static String cmdToString(PlainComponentSerializer serializer, String prefix, Command c, int indent) { - return serializer.serialize(TextComponent.of(prefix + c.getName()).append(TextComponent.newline()) - .append(TextComponent.of(c.getCondition() instanceof PermissionCondition - ? "Permissions: " + (String.join(", ", ((PermissionCondition) c.getCondition()).getPermissions())) + "\n" - : "")) - .append(c.getFullHelp())).replace("\n", "\n" + Strings.repeat("\t", indent)); - } - } From b7e329bc1b2c5b4516d47e9a3d80a2f42cd68a59 Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 5 Jun 2019 10:39:10 -0400 Subject: [PATCH 181/366] Better spacing for section headers. --- .../com/sk89q/worldedit/internal/util/DocumentationPrinter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java index 8c2bdb46f..f5ac335f2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java @@ -350,7 +350,7 @@ public final class DocumentationPrinter { } private void dumpSection(String title, CommandManager manager) { - cmdOutput.append(title).append("\n").append(Strings.repeat("~", title.length())).append("\n\n"); + cmdOutput.append("\n").append(title).append("\n").append(Strings.repeat("~", title.length())).append("\n"); String prefix = TextConfig.getCommandPrefix(); From 22157f08644cf0081ec57fb6bd5ba6eb4d018e27 Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 5 Jun 2019 11:27:16 -0400 Subject: [PATCH 182/366] Write entire perms file for easier gen. Also fix some format issues. --- .../internal/util/DocumentationPrinter.java | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java index f5ac335f2..8b29bb51f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java @@ -322,6 +322,8 @@ public final class DocumentationPrinter { new UtilityCommands(worldEdit) ); dumpSection("Utility Commands", manager); + + writeFooter(); } private void writeHeader() { @@ -336,6 +338,42 @@ public final class DocumentationPrinter { ".. tip::\n" + "\n" + " Arguments enclosed in ``[ ]`` are optional, those enclosed in ``< >`` are required.\n\n"); + + permsOutput.append("===========\n" + + "Permissions\n" + + "===========\n" + + "\n" + + "By default, no one can use WorldEdit. In order for yourself, moderators, and players to use WorldEdit, you must provide the proper permissions. One way is to provide op to moderators and administrators (unless disabled in the :doc:`configuration `), but providing the permission nodes on this page (through a permissions plugin) is the more flexible.\n" + + "\n" + + "You can give the ``worldedit.*`` permission to give yourself and other administrators full access to WorldEdit.\n" + + "\n" + + "Commands\n" + + "=========\n" + + "\n" + + "See the :doc:`commands` page for an explanation of some of these commands.\n" + + "\n" + + ".. csv-table::\n" + + " :header: Command, Permission\n" + + " :widths: 15, 25\n\n"); + } + + private void writeFooter() { + permsOutput.append("\nOther Permissions\n" + + "==================\n" + + "\n" + + ".. csv-table::\n" + + " :header: Permission, Explanation\n" + + " :widths: 15, 25\n" + + "\n" + + " worldedit.navigation.jumpto.tool,\"Allows usage of the navigation wand's ``/jumpto`` shortcut (left click).\"\n" + + " worldedit.navigation.thru.tool,\"Allows usage of the navigation wand's ``/thru`` shortcut (right click).\"\n" + + " worldedit.anyblock,\"Allows usage of blocks in the :doc:`disallowed-blocks ` config option.\"\n" + + " worldedit.limit.unrestricted,\"Allows setting the limit via the ``//limit`` :doc:`command ` higher than the maximum in the :doc:`configuration `.\"\n" + + " worldedit.timeout.unrestricted,\"Allows setting the calculation timeout via the ``//timeout`` :doc:`command ` higher than the maximum in the :doc:`configuration `.\"\n" + + " worldedit.inventory.unrestricted,\"Override the ``use-inventory`` option if enabled in the :doc:`configuration `.\"\n" + + " worldedit.override.bedrock,\"Allows breaking of bedrock with the super-pickaxe tool.\"\n" + + " worldedit.setnbt,\"Allows setting `extra data `_ on blocks (such as signs, chests, etc).\"\n" + + " worldedit.report.pastebin,\"Allows uploading report files to pastebin automatically for the ``/worldedit report`` :doc:`command `.\""); } private CommandManager createManager() { @@ -357,8 +395,10 @@ public final class DocumentationPrinter { // permsOutput.append("\n------------\n\n"); cmdsToPerms(manager.getAllCommands(), prefix); + boolean first = true; for (Command command : manager.getAllCommands().collect(Collectors.toList())) { - cmdOutput.append("\n------------\n\n"); + if (!first) cmdOutput.append("\n------------\n\n"); + first = false; writeCommandBlock(command, prefix, Stream.empty()); command.getParts().stream().filter(p -> p instanceof SubCommandPart) .flatMap(p -> ((SubCommandPart) p).getCommands().stream()) From e767dd98881fc75d1bd5ce68a388adf3605cff66 Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 5 Jun 2019 12:31:12 -0400 Subject: [PATCH 183/366] Missing perm. --- .../src/main/java/com/sk89q/worldedit/LocalConfiguration.java | 4 ++-- .../sk89q/worldedit/internal/util/DocumentationPrinter.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index 08594fcfb..d814bf48b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -54,7 +54,7 @@ public abstract class LocalConfiguration { public boolean logCommands = false; public String logFile = ""; public String logFormat = LogFormat.DEFAULT_FORMAT; - public boolean registerHelp = true; // what is the point of this, it's not even used + public boolean registerHelp = true; // unused public String wandItem = "minecraft:wooden_axe"; public boolean superPickaxeDrop = true; public boolean superPickaxeManyDrop = true; @@ -70,7 +70,7 @@ public abstract class LocalConfiguration { public Set allowedDataCycleBlocks = new HashSet<>(); public String saveDir = "schematics"; public String scriptsDir = "craftscripts"; - public boolean showHelpInfo = true; + public boolean showHelpInfo = true; // unused public int butcherDefaultRadius = -1; public int butcherMaxRadius = -1; public boolean allowSymlinks = false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java index 8b29bb51f..6352451f9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java @@ -368,10 +368,11 @@ public final class DocumentationPrinter { " worldedit.navigation.jumpto.tool,\"Allows usage of the navigation wand's ``/jumpto`` shortcut (left click).\"\n" + " worldedit.navigation.thru.tool,\"Allows usage of the navigation wand's ``/thru`` shortcut (right click).\"\n" + " worldedit.anyblock,\"Allows usage of blocks in the :doc:`disallowed-blocks ` config option.\"\n" + - " worldedit.limit.unrestricted,\"Allows setting the limit via the ``//limit`` :doc:`command ` higher than the maximum in the :doc:`configuration `.\"\n" + + " worldedit.limit.unrestricted,\"Allows setting the limit via the ``//limit`` :doc:`command ` higher than the maximum in the :doc:`configuration `, as well as other limit bypasses.\"\n" + " worldedit.timeout.unrestricted,\"Allows setting the calculation timeout via the ``//timeout`` :doc:`command ` higher than the maximum in the :doc:`configuration `.\"\n" + " worldedit.inventory.unrestricted,\"Override the ``use-inventory`` option if enabled in the :doc:`configuration `.\"\n" + " worldedit.override.bedrock,\"Allows breaking of bedrock with the super-pickaxe tool.\"\n" + + " worldedit.override.data-cycler,\"Allows cycling non-whitelisted blocks with the data cycler tool.\"\n" + " worldedit.setnbt,\"Allows setting `extra data `_ on blocks (such as signs, chests, etc).\"\n" + " worldedit.report.pastebin,\"Allows uploading report files to pastebin automatically for the ``/worldedit report`` :doc:`command `.\""); } From e69aedf05964c8e3906a2426260e95423157109e Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 5 Jun 2019 14:57:44 -0400 Subject: [PATCH 184/366] Allow clean shutdown. Rearrange command tables. --- .../internal/util/DocumentationPrinter.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java index 6352451f9..cd378d57e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java @@ -103,6 +103,8 @@ public final class DocumentationPrinter { printer.writeAllCommands(); writeOutput("commands.rst", printer.cmdOutput.toString()); writeOutput("permissions.rst", printer.permsOutput.toString()); + + WorldEdit.getInstance().getSessionManager().unload(); } private static void writeOutput(String file, String output) throws IOException { @@ -427,12 +429,14 @@ public final class DocumentationPrinter { String name = prefix + command.getName(); String desc = serializer.serialize(command.getDescription()); cmdOutput.append(".. csv-table::\n :widths: 8, 15\n\n"); - cmdOutput.append(" ").append(name).append(",\"").append(desc).append("\"\n"); + cmdOutput.append(" ").append(name).append(","); if (!command.getAliases().isEmpty()) { - cmdOutput.append(" Aliases,\"").append(String.join(", ", - command.getAliases().stream().map(a -> prefix + a).collect(Collectors.toSet()))) - .append("\"\n"); + cmdOutput.append("\"(or ").append(String.join(", ", + command.getAliases().stream().map(a -> prefix + a).collect(Collectors.toSet()))) + .append(")\""); } + cmdOutput.append("\n"); + cmdOutput.append(" Description,\"").append(desc).append("\"\n"); if (command.getCondition() instanceof PermissionCondition) { cmdOutput.append(" Permissions,\"").append(String.join(", ", ((PermissionCondition) command.getCondition()).getPermissions())).append("\"\n"); } From d46cd78e14b4ceb3fce423d2a04b589ed9266cd9 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 5 Jun 2019 23:26:57 -0700 Subject: [PATCH 185/366] Port doc printer to Kotlin, heavily improve --- settings.gradle | 2 + worldedit-core/doctools/build.gradle.kts | 19 + .../internal/util/DocumentationPrinter.kt | 320 +++++++++++++ .../internal/util/DocumentationPrinter.java | 452 ------------------ 4 files changed, 341 insertions(+), 452 deletions(-) create mode 100644 worldedit-core/doctools/build.gradle.kts create mode 100644 worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java diff --git a/settings.gradle b/settings.gradle index 84386e427..dec0467a5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,3 +7,5 @@ include 'worldedit-libs' include "worldedit-$it" } include "worldedit-libs:core:ap" + +include "worldedit-core:doctools" diff --git a/worldedit-core/doctools/build.gradle.kts b/worldedit-core/doctools/build.gradle.kts new file mode 100644 index 000000000..002f367bd --- /dev/null +++ b/worldedit-core/doctools/build.gradle.kts @@ -0,0 +1,19 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.3.31" +} + +tasks.withType { + kotlinOptions.jvmTarget = "1.8" +} + +repositories { + jcenter() +} + +dependencies { + "implementation"(project(":worldedit-libs:core:ap")) + "implementation"(project(":worldedit-core")) + "implementation"(kotlin("stdlib-jdk8")) +} diff --git a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt new file mode 100644 index 000000000..167d0cb34 --- /dev/null +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt @@ -0,0 +1,320 @@ +/* + * 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.internal.util + +import com.google.common.base.Strings +import com.sk89q.worldedit.WorldEdit +import com.sk89q.worldedit.command.BiomeCommands +import com.sk89q.worldedit.command.ChunkCommands +import com.sk89q.worldedit.command.ClipboardCommands +import com.sk89q.worldedit.command.ExpandCommands +import com.sk89q.worldedit.command.GeneralCommands +import com.sk89q.worldedit.command.GenerationCommands +import com.sk89q.worldedit.command.HistoryCommands +import com.sk89q.worldedit.command.NavigationCommands +import com.sk89q.worldedit.command.RegionCommands +import com.sk89q.worldedit.command.ScriptingCommands +import com.sk89q.worldedit.command.SelectionCommands +import com.sk89q.worldedit.command.SnapshotUtilCommands +import com.sk89q.worldedit.command.ToolCommands +import com.sk89q.worldedit.command.ToolUtilCommands +import com.sk89q.worldedit.command.UtilityCommands +import com.sk89q.worldedit.command.util.PermissionCondition +import com.sk89q.worldedit.util.formatting.text.TextComponent +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent +import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer +import org.enginehub.piston.Command +import org.enginehub.piston.TextConfig +import org.enginehub.piston.part.SubCommandPart +import org.enginehub.piston.util.HelpGenerator +import java.nio.file.Files +import java.nio.file.Paths +import java.util.stream.Stream +import kotlin.streams.toList +import org.enginehub.piston.annotation.Command as CommandAnnotation + +class DocumentationPrinter private constructor() { + + private val serializer = PlainComponentSerializer({ "" }, TranslatableComponent::key) + private val commands = WorldEdit.getInstance().platformManager.platformCommandManager.commandManager.allCommands + .map { it.name to it }.toList().toMap() + private val cmdOutput = StringBuilder() + private val permsOutput = StringBuilder() + + private suspend inline fun SequenceScope.yieldAllCommandsIn() { + for (method in T::class.java.methods) { + val cmdAnno = method.getDeclaredAnnotation(CommandAnnotation::class.java) + if (cmdAnno != null) { + yield(cmdAnno.name) + } + } + } + + private fun writeAllCommands() { + writeHeader() + + dumpSection("General Commands") { + yield("worldedit") + yieldAllCommandsIn() + yieldAllCommandsIn() + } + + dumpSection("Navigation Commands") { + yieldAllCommandsIn() + } + + dumpSection("Selection Commands") { + yieldAllCommandsIn() + yieldAllCommandsIn() + } + + dumpSection("Region Commands") { + yieldAllCommandsIn() + } + + dumpSection("Generation Commands") { + yieldAllCommandsIn() + } + + dumpSection("Schematic and Clipboard Commands") { + yield("schematic") + yieldAllCommandsIn() + } + + dumpSection("Tool Commands") { + yieldAllCommandsIn() + yieldAllCommandsIn() + } + + dumpSection("Super Pickaxe Commands") { + yield("superpickaxe") + } + + dumpSection("Brush Commands") { + yield("brush") + } + + dumpSection("Biome Commands") { + yieldAllCommandsIn() + } + + dumpSection("Chunk Commands") { + yieldAllCommandsIn() + } + + dumpSection("Snapshot Commands") { + yieldAllCommandsIn() + yield("snapshot") + } + + dumpSection("Scripting Commands") { + yieldAllCommandsIn() + } + + dumpSection("Utility Commands") { + yieldAllCommandsIn() + } + + writeFooter() + } + + private fun writeHeader() { + cmdOutput.appendln(""" +======== +Commands +======== + +.. contents:: + :local: + +.. tip:: + + Arguments enclosed in ``[ ]`` are optional, those enclosed in ``< >`` are required. +""".trim()) + + permsOutput.appendln(""" +=========== +Permissions +=========== + +By default, no one can use WorldEdit. In order for yourself, moderators, and players to use WorldEdit, you must provide the proper permissions. One way is to provide op to moderators and administrators (unless disabled in the :doc:`configuration `), but providing the permission nodes on this page (through a permissions plugin) is the more flexible. + +You can give the ``worldedit.*`` permission to give yourself and other administrators full access to WorldEdit. + +Commands +========= + +See the :doc:`commands` page for an explanation of some of these commands. + +.. csv-table:: + :header: Command, Permission + :widths: 15, 25 +""".trim()) + permsOutput.appendln() + } + + private fun writeFooter() { + permsOutput.appendln() + permsOutput.append(""" +Other Permissions +================== + +.. csv-table:: + :header: Permission, Explanation + :widths: 15, 25 + + ``worldedit.navigation.jumpto.tool``,"Allows usage of the navigation wand's ``/jumpto`` shortcut (left click)." + ``worldedit.navigation.thru.tool``,"Allows usage of the navigation wand's ``/thru`` shortcut (right click)." + ``worldedit.anyblock``,"Allows usage of blocks in the :doc:`disallowed-blocks ` config option." + ``worldedit.limit.unrestricted``,"Allows setting the limit via the ``//limit`` :doc:`command ` higher than the maximum in the :doc:`configuration `, as well as other limit bypasses." + ``worldedit.timeout.unrestricted``,"Allows setting the calculation timeout via the ``//timeout`` :doc:`command ` higher than the maximum in the :doc:`configuration `." + ``worldedit.inventory.unrestricted``,"Override the ``use-inventory`` option if enabled in the :doc:`configuration `." + ``worldedit.override.bedrock``,"Allows breaking of bedrock with the super-pickaxe tool." + ``worldedit.override.data-cycler``,"Allows cycling non-whitelisted blocks with the data cycler tool." + ``worldedit.setnbt``,"Allows setting `extra data `_ on blocks (such as signs, chests, etc)." + ``worldedit.report.pastebin``,"Allows uploading report files to pastebin automatically for the ``/worldedit report`` :doc:`command `." +""".trim()) + } + + private fun dumpSection(title: String, addCommandNames: suspend SequenceScope.() -> Unit) { + cmdOutput.append("\n").append(title).append("\n").append(Strings.repeat("~", title.length)).append("\n") + + val prefix = TextConfig.getCommandPrefix() + val commands = sequence(addCommandNames).map { this.commands.getValue(it) }.toList() + + cmdsToPerms(commands, prefix) + + for (command in commands) { + writeCommandBlock(command, prefix, Stream.empty()) + command.parts.stream().filter { p -> p is SubCommandPart } + .flatMap { p -> (p as SubCommandPart).commands.stream() } + .forEach { sc -> + writeCommandBlock(sc, prefix + command.name + " ", Stream.of(command)) + } + } + } + + private fun cmdsToPerms(cmds: List, prefix: String) { + cmds.forEach { c -> + permsOutput.append(" ").append(cmdToPerm(prefix, c)).append("\n") + c.parts.filter { p -> p is SubCommandPart } + .map { p -> p as SubCommandPart } + .forEach { scp -> + cmdsToPerms(scp.commands.sortedBy { it.name }, prefix + c.name + " ") + } + } + } + + private fun cmdToPerm(prefix: String, c: Command): String { + val cond = c.condition + val permissions = when { + cond is PermissionCondition && cond.permissions.isNotEmpty() -> + cond.permissions.joinToString(", ") { "``$it``" } + else -> "" + } + return "``$prefix${c.name}``,\"$permissions\"" + } + + private fun writeCommandBlock(command: Command, prefix: String, parents: Stream) { + val name = prefix + command.name + val entries = commandTableEntries(command, parents) + + cmdOutput.appendln(".. raw:: html") + cmdOutput.appendln() + cmdOutput.appendln(""" """) + cmdOutput.appendln() + cmdOutput.append(".. topic:: ``$name``") + if (!command.aliases.isEmpty()) { + command.aliases.joinTo(cmdOutput, ", ", + prefix = " (or ", + postfix = ")", + transform = { "``$prefix$it``" }) + } + cmdOutput.appendln().appendln() + cmdOutput.appendln(""" + | .. csv-table:: + | :widths: 8, 15 + """.trimMargin()) + cmdOutput.appendln() + for ((k, v) in entries) { + val rstSafe = v.replace("\"", "\\\"").replace("\n", "\n" + " ".repeat(2)) + cmdOutput.append(" ".repeat(2)) + .append(k) + .append(",") + .append('"') + .append(rstSafe) + .append('"').appendln() + } + cmdOutput.appendln() + } + + private fun linkSafe(text: String) = text.replace(" ", "-") + + private fun commandTableEntries(command: Command, parents: Stream): Map { + return sequence { + val desc = command.description.run { + when { + command.footer.isPresent -> append( + TextComponent.builder("\n\n").append(command.footer.get()) + ) + else -> this + } + } + yield("**Description**" to serializer.serialize(desc)) + val cond = command.condition + if (cond is PermissionCondition && cond.permissions.isNotEmpty()) { + val perms = cond.permissions.joinToString(", ") { "``$it``" } + yield("**Permissions**" to perms) + } + val usage = serializer.serialize(HelpGenerator.create(Stream.concat(parents, Stream.of(command)).toList()).usage) + yield("**Usage**" to "``$usage``") + + // Part descriptions + command.parts.filterNot { it is SubCommandPart } + .forEach { + val title = "\u2001\u2001``" + serializer.serialize(it.textRepresentation) + "``" + yield(title to serializer.serialize(it.description)) + } + }.toMap() + } + + companion object { + + /** + * Generates documentation. + */ + @JvmStatic + fun main(args: Array) { + val printer = DocumentationPrinter() + + printer.writeAllCommands() + writeOutput("commands.rst", printer.cmdOutput.toString()) + writeOutput("permissions.rst", printer.permsOutput.toString()) + + WorldEdit.getInstance().sessionManager.unload() + } + + private fun writeOutput(file: String, output: String) { + Files.newBufferedWriter(Paths.get(file)).use { + it.write(output) + } + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java deleted file mode 100644 index cd378d57e..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/DocumentationPrinter.java +++ /dev/null @@ -1,452 +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 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.internal.util; - -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.io.Files; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.command.ApplyBrushCommands; -import com.sk89q.worldedit.command.BiomeCommands; -import com.sk89q.worldedit.command.BiomeCommandsRegistration; -import com.sk89q.worldedit.command.BrushCommands; -import com.sk89q.worldedit.command.BrushCommandsRegistration; -import com.sk89q.worldedit.command.ChunkCommands; -import com.sk89q.worldedit.command.ChunkCommandsRegistration; -import com.sk89q.worldedit.command.ClipboardCommands; -import com.sk89q.worldedit.command.ClipboardCommandsRegistration; -import com.sk89q.worldedit.command.ExpandCommands; -import com.sk89q.worldedit.command.GeneralCommands; -import com.sk89q.worldedit.command.GeneralCommandsRegistration; -import com.sk89q.worldedit.command.GenerationCommands; -import com.sk89q.worldedit.command.GenerationCommandsRegistration; -import com.sk89q.worldedit.command.HistoryCommands; -import com.sk89q.worldedit.command.HistoryCommandsRegistration; -import com.sk89q.worldedit.command.NavigationCommands; -import com.sk89q.worldedit.command.NavigationCommandsRegistration; -import com.sk89q.worldedit.command.PaintBrushCommands; -import com.sk89q.worldedit.command.RegionCommands; -import com.sk89q.worldedit.command.RegionCommandsRegistration; -import com.sk89q.worldedit.command.SchematicCommands; -import com.sk89q.worldedit.command.SchematicCommandsRegistration; -import com.sk89q.worldedit.command.ScriptingCommands; -import com.sk89q.worldedit.command.ScriptingCommandsRegistration; -import com.sk89q.worldedit.command.SelectionCommands; -import com.sk89q.worldedit.command.SelectionCommandsRegistration; -import com.sk89q.worldedit.command.SnapshotCommands; -import com.sk89q.worldedit.command.SnapshotCommandsRegistration; -import com.sk89q.worldedit.command.SnapshotUtilCommands; -import com.sk89q.worldedit.command.SnapshotUtilCommandsRegistration; -import com.sk89q.worldedit.command.SuperPickaxeCommands; -import com.sk89q.worldedit.command.SuperPickaxeCommandsRegistration; -import com.sk89q.worldedit.command.ToolCommands; -import com.sk89q.worldedit.command.ToolCommandsRegistration; -import com.sk89q.worldedit.command.ToolUtilCommands; -import com.sk89q.worldedit.command.ToolUtilCommandsRegistration; -import com.sk89q.worldedit.command.UtilityCommands; -import com.sk89q.worldedit.command.UtilityCommandsRegistration; -import com.sk89q.worldedit.command.WorldEditCommands; -import com.sk89q.worldedit.command.WorldEditCommandsRegistration; -import com.sk89q.worldedit.command.util.PermissionCondition; -import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; -import com.sk89q.worldedit.util.formatting.text.serializer.ComponentSerializer; -import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer; -import org.enginehub.piston.Command; -import org.enginehub.piston.CommandManager; -import org.enginehub.piston.TextConfig; -import org.enginehub.piston.gen.CommandRegistration; -import org.enginehub.piston.impl.CommandManagerImpl; -import org.enginehub.piston.impl.CommandManagerServiceImpl; -import org.enginehub.piston.part.SubCommandPart; -import org.enginehub.piston.util.HelpGenerator; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public final class DocumentationPrinter { - - /** - * Generates documentation. - * - * @param args arguments - */ - public static void main(String[] args) throws IOException { - final DocumentationPrinter printer = new DocumentationPrinter(); - - printer.writeAllCommands(); - writeOutput("commands.rst", printer.cmdOutput.toString()); - writeOutput("permissions.rst", printer.permsOutput.toString()); - - WorldEdit.getInstance().getSessionManager().unload(); - } - - private static void writeOutput(String file, String output) throws IOException { - File outfile = new File(file); - Files.write(output, outfile, StandardCharsets.UTF_8); - } - - private final ComponentSerializer serializer - = new PlainComponentSerializer(kb -> "", TranslatableComponent::key); - private final CommandRegistrationHandler registration; - private final CommandManagerServiceImpl commandManagerService; - private final WorldEdit worldEdit = WorldEdit.getInstance(); - private StringBuilder cmdOutput; - private StringBuilder permsOutput; - private Field mgrCmdField; - - private DocumentationPrinter() { - this.cmdOutput = new StringBuilder(); - this.permsOutput = new StringBuilder(); - this.registration = new CommandRegistrationHandler(ImmutableList.of()); - this.commandManagerService = new CommandManagerServiceImpl(); - try { - Field field = CommandManagerImpl.class.getDeclaredField("commands"); - field.setAccessible(true); - this.mgrCmdField = field; - } catch (NoSuchFieldException ignored) { - } - } - - private void registerSubCommands(CommandManager parent, String name, List aliases, String desc, - CommandRegistration registration, CI instance) { - registerSubCommands(parent, name, aliases, desc, registration, instance, m -> {}); - } - - private void registerSubCommands(CommandManager parent, String name, List aliases, String desc, - CommandRegistration registration, CI instance, - Consumer additionalConfig) { - parent.register(name, cmd -> { - cmd.aliases(aliases); - cmd.description(TextComponent.of(desc)); - cmd.action(Command.Action.NULL_ACTION); - - CommandManager manager = createManager(); - this.registration.register( - manager, - registration, - instance - ); - additionalConfig.accept(manager); - - cmd.addPart(SubCommandPart.builder(TranslatableComponent.of("worldedit.argument.action"), - TextComponent.of("Sub-command to run.")) - .withCommands(manager.getAllCommands().collect(Collectors.toList())) - .required() - .build()); - }); - } - - private void writeAllCommands() { - writeHeader(); - - CommandManager manager; - - manager = createManager(); - registerSubCommands( - manager, - "worldedit", - ImmutableList.of("we"), - "WorldEdit commands", - WorldEditCommandsRegistration.builder(), - new WorldEditCommands(worldEdit) - ); - this.registration.register( - manager, - HistoryCommandsRegistration.builder(), - new HistoryCommands(worldEdit) - ); - this.registration.register( - manager, - GeneralCommandsRegistration.builder(), - new GeneralCommands(worldEdit) - ); - dumpSection("General Commands", manager); - - manager = createManager(); - this.registration.register( - manager, - NavigationCommandsRegistration.builder(), - new NavigationCommands(worldEdit) - ); - dumpSection("Navigation Commands", manager); - - manager = createManager(); - this.registration.register( - manager, - SelectionCommandsRegistration.builder(), - new SelectionCommands(worldEdit) - ); - ExpandCommands.register(registration, manager, commandManagerService); - dumpSection("Selection Commands", manager); - - manager = createManager(); - this.registration.register( - manager, - RegionCommandsRegistration.builder(), - new RegionCommands() - ); - dumpSection("Region Commands", manager); - - manager = createManager(); - this.registration.register( - manager, - GenerationCommandsRegistration.builder(), - new GenerationCommands(worldEdit) - ); - dumpSection("Generation Commands", manager); - - manager = createManager(); - registerSubCommands( - manager, - "schematic", - ImmutableList.of("schem", "/schematic", "/schem"), - "Schematic commands for saving/loading areas", - SchematicCommandsRegistration.builder(), - new SchematicCommands(worldEdit) - ); - this.registration.register( - manager, - ClipboardCommandsRegistration.builder(), - new ClipboardCommands() - ); - dumpSection("Schematic and Clipboard Commands", manager); - - manager = createManager(); - this.registration.register( - manager, - ToolCommandsRegistration.builder(), - new ToolCommands(worldEdit) - ); - this.registration.register( - manager, - ToolUtilCommandsRegistration.builder(), - new ToolUtilCommands(worldEdit) - ); - dumpSection("Tool Commands", manager); - - manager = createManager(); - registerSubCommands( - manager, - "superpickaxe", - ImmutableList.of("pickaxe", "sp"), - "Super-pickaxe commands", - SuperPickaxeCommandsRegistration.builder(), - new SuperPickaxeCommands(worldEdit) - ); - dumpSection("Super Pickaxe Commands", manager); - - manager = createManager(); - registerSubCommands( - manager, - "brush", - ImmutableList.of("br", "/brush", "/br"), - "Brushing commands", - BrushCommandsRegistration.builder(), - new BrushCommands(worldEdit), - mgr -> { - PaintBrushCommands.register(commandManagerService, mgr, registration); - ApplyBrushCommands.register(commandManagerService, mgr, registration); - } - ); - dumpSection("Brush Commands", manager); - - manager = createManager(); - this.registration.register( - manager, - BiomeCommandsRegistration.builder(), - new BiomeCommands() - ); - dumpSection("Biome Commands", manager); - - manager = createManager(); - this.registration.register( - manager, - ChunkCommandsRegistration.builder(), - new ChunkCommands(worldEdit) - ); - dumpSection("Chunk Commands", manager); - - manager = createManager(); - this.registration.register( - manager, - SnapshotUtilCommandsRegistration.builder(), - new SnapshotUtilCommands(worldEdit) - ); - registerSubCommands( - manager, - "snapshot", - ImmutableList.of("snap"), - "Snapshot commands for restoring backups", - SnapshotCommandsRegistration.builder(), - new SnapshotCommands(worldEdit) - ); - dumpSection("Snapshot Commands", manager); - - manager = createManager(); - this.registration.register( - manager, - ScriptingCommandsRegistration.builder(), - new ScriptingCommands(worldEdit) - ); - dumpSection("Scripting Commands", manager); - - manager = createManager(); - this.registration.register( - manager, - UtilityCommandsRegistration.builder(), - new UtilityCommands(worldEdit) - ); - dumpSection("Utility Commands", manager); - - writeFooter(); - } - - private void writeHeader() { - cmdOutput.append( - "========\n" + - "Commands\n" + - "========\n" + - "\n" + - ".. contents::\n" + - " :local:\n" + - "\n" + - ".. tip::\n" + - "\n" + - " Arguments enclosed in ``[ ]`` are optional, those enclosed in ``< >`` are required.\n\n"); - - permsOutput.append("===========\n" + - "Permissions\n" + - "===========\n" + - "\n" + - "By default, no one can use WorldEdit. In order for yourself, moderators, and players to use WorldEdit, you must provide the proper permissions. One way is to provide op to moderators and administrators (unless disabled in the :doc:`configuration `), but providing the permission nodes on this page (through a permissions plugin) is the more flexible.\n" + - "\n" + - "You can give the ``worldedit.*`` permission to give yourself and other administrators full access to WorldEdit.\n" + - "\n" + - "Commands\n" + - "=========\n" + - "\n" + - "See the :doc:`commands` page for an explanation of some of these commands.\n" + - "\n" + - ".. csv-table::\n" + - " :header: Command, Permission\n" + - " :widths: 15, 25\n\n"); - } - - private void writeFooter() { - permsOutput.append("\nOther Permissions\n" + - "==================\n" + - "\n" + - ".. csv-table::\n" + - " :header: Permission, Explanation\n" + - " :widths: 15, 25\n" + - "\n" + - " worldedit.navigation.jumpto.tool,\"Allows usage of the navigation wand's ``/jumpto`` shortcut (left click).\"\n" + - " worldedit.navigation.thru.tool,\"Allows usage of the navigation wand's ``/thru`` shortcut (right click).\"\n" + - " worldedit.anyblock,\"Allows usage of blocks in the :doc:`disallowed-blocks ` config option.\"\n" + - " worldedit.limit.unrestricted,\"Allows setting the limit via the ``//limit`` :doc:`command ` higher than the maximum in the :doc:`configuration `, as well as other limit bypasses.\"\n" + - " worldedit.timeout.unrestricted,\"Allows setting the calculation timeout via the ``//timeout`` :doc:`command ` higher than the maximum in the :doc:`configuration `.\"\n" + - " worldedit.inventory.unrestricted,\"Override the ``use-inventory`` option if enabled in the :doc:`configuration `.\"\n" + - " worldedit.override.bedrock,\"Allows breaking of bedrock with the super-pickaxe tool.\"\n" + - " worldedit.override.data-cycler,\"Allows cycling non-whitelisted blocks with the data cycler tool.\"\n" + - " worldedit.setnbt,\"Allows setting `extra data `_ on blocks (such as signs, chests, etc).\"\n" + - " worldedit.report.pastebin,\"Allows uploading report files to pastebin automatically for the ``/worldedit report`` :doc:`command `.\""); - } - - private CommandManager createManager() { - final CommandManager commandManager = commandManagerService.newCommandManager(); - if (mgrCmdField != null && commandManager instanceof CommandManagerImpl) { - try { - mgrCmdField.set(commandManager, new LinkedHashMap<>()); - } catch (IllegalAccessException ignored) { - } - } - return commandManager; - } - - private void dumpSection(String title, CommandManager manager) { - cmdOutput.append("\n").append(title).append("\n").append(Strings.repeat("~", title.length())).append("\n"); - - String prefix = TextConfig.getCommandPrefix(); - -// permsOutput.append("\n------------\n\n"); - cmdsToPerms(manager.getAllCommands(), prefix); - - boolean first = true; - for (Command command : manager.getAllCommands().collect(Collectors.toList())) { - if (!first) cmdOutput.append("\n------------\n\n"); - first = false; - writeCommandBlock(command, prefix, Stream.empty()); - command.getParts().stream().filter(p -> p instanceof SubCommandPart) - .flatMap(p -> ((SubCommandPart) p).getCommands().stream()) - .forEach(sc -> { - cmdOutput.append("\n------------\n\n"); - writeCommandBlock(sc, prefix + command.getName() + " ", Stream.of(command)); - }); - } - } - - private void cmdsToPerms(Stream cmds, String prefix) { - cmds.forEach(c -> { - permsOutput.append(" ").append(cmdToPerm(prefix, c)).append("\n"); - c.getParts().stream().filter(p -> p instanceof SubCommandPart).map(p -> (SubCommandPart) p) - .forEach(scp -> cmdsToPerms(scp.getCommands().stream(), prefix + c.getName() + " ")); - }); - } - - private String cmdToPerm(String prefix, Command c) { - return prefix + c.getName() + ",\"" + (c.getCondition() instanceof PermissionCondition - ? String.join(", ", ((PermissionCondition) c.getCondition()).getPermissions()) : "") + "\""; - } - - private void writeCommandBlock(Command command, String prefix, Stream parents) { - String name = prefix + command.getName(); - String desc = serializer.serialize(command.getDescription()); - cmdOutput.append(".. csv-table::\n :widths: 8, 15\n\n"); - cmdOutput.append(" ").append(name).append(","); - if (!command.getAliases().isEmpty()) { - cmdOutput.append("\"(or ").append(String.join(", ", - command.getAliases().stream().map(a -> prefix + a).collect(Collectors.toSet()))) - .append(")\""); - } - cmdOutput.append("\n"); - cmdOutput.append(" Description,\"").append(desc).append("\"\n"); - if (command.getCondition() instanceof PermissionCondition) { - cmdOutput.append(" Permissions,\"").append(String.join(", ", ((PermissionCondition) command.getCondition()).getPermissions())).append("\"\n"); - } - cmdOutput.append(" Usage,\"").append(serializer.serialize( - HelpGenerator.create(Stream.concat(parents, Stream.of(command)).collect(Collectors.toList())).getUsage())).append("\"\n"); - command.getParts().stream().filter(part -> !(part instanceof SubCommandPart)).forEach(part -> - cmdOutput.append(" \u2001\u2001").append(serializer.serialize(part.getTextRepresentation())).append(",\"") - .append(serializer.serialize(part.getDescription())).append("\"\n")); - if (command.getFooter().isPresent()) { - cmdOutput.append(" ,\"").append(serializer.serialize(command.getFooter().get()).replace("\n", " ")).append("\"\n"); - } - } -} From 351fd6771ac3459bfd3d5eef1bb1a00391fab87f Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 6 Jun 2019 10:34:12 -0400 Subject: [PATCH 186/366] Restore ability to restore old MCRegion files. --- .../com/sk89q/worldedit/world/storage/ChunkStore.java | 2 +- .../worldedit/world/storage/McRegionChunkStore.java | 2 +- .../world/storage/TrueZipMcRegionChunkStore.java | 11 +++++++++-- .../world/storage/ZippedMcRegionChunkStore.java | 11 +++++++++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java index edd0799b4..1b89c8b09 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ChunkStore.java @@ -109,7 +109,7 @@ public abstract class ChunkStore implements Closeable { if (dataVersion == 0) dataVersion = -1; final Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING); final int currentDataVersion = platform.getDataVersion(); - if (dataVersion < currentDataVersion) { + if (tag.getValue().containsKey("Sections") && dataVersion < currentDataVersion) { // only fix up MCA format, DFU doesn't support MCR chunks final DataFixer dataFixer = platform.getDataFixer(); if (dataFixer != null) { return new AnvilChunk13((CompoundTag) dataFixer.fixUp(DataFixer.FixTypes.CHUNK, rootTag, dataVersion).getValue().get("Level")); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java index 5c4eabfd9..a80a05e2f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionChunkStore.java @@ -78,7 +78,7 @@ public abstract class McRegionChunkStore extends ChunkStore { throw new ChunkStoreException("CompoundTag expected for chunk; got " + tag.getClass().getName()); } - return (CompoundTag)tag; + return (CompoundTag) tag; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java index 8d7c03e93..80e2f814d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java @@ -115,7 +115,14 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore { ZipEntry entry = getEntry(name); if (entry == null) { - throw new MissingChunkException(); + if (name.endsWith(".mca")) { // try old mcr format + entry = getEntry(name.replace(".mca", ".mcr")); + if (entry == null) { + throw new MissingChunkException(); + } + } else { + throw new MissingChunkException(); + } } try { return zip.getInputStream(entry); @@ -150,7 +157,7 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore { ZipEntry testEntry = e.nextElement(); - if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { // TODO: does this need a separate class? + if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { return true; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java index 581686ea4..afb9cff72 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java @@ -102,7 +102,14 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore { ZipEntry entry = getEntry(name); if (entry == null) { - throw new MissingChunkException(); + if (name.endsWith(".mca")) { // try old mcr format + entry = getEntry(name.replace(".mca", ".mcr")); + if (entry == null) { + throw new MissingChunkException(); + } + } else { + throw new MissingChunkException(); + } } try { return zip.getInputStream(entry); @@ -136,7 +143,7 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore { ZipEntry testEntry = e.nextElement(); - if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { // TODO: does this need a separate class? + if (testEntry.getName().matches(".*\\.mcr$") || testEntry.getName().matches(".*\\.mca$")) { return true; } } From 8022d8e9115b65bc822d564238752c76df64a48e Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 6 Jun 2019 13:22:18 -0400 Subject: [PATCH 187/366] Use ItemInteract for item right clicks in Sponge. They don't fire for InteractBlock. # Conflicts: # worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java --- .../worldedit/sponge/SpongeWorldEdit.java | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java index f3133fb13..672eed9fe 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java @@ -51,6 +51,7 @@ import org.spongepowered.api.event.game.state.GamePostInitializationEvent; import org.spongepowered.api.event.game.state.GamePreInitializationEvent; import org.spongepowered.api.event.game.state.GameStartedServerEvent; import org.spongepowered.api.event.game.state.GameStoppingServerEvent; +import org.spongepowered.api.event.item.inventory.InteractItemEvent; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.plugin.Plugin; @@ -204,6 +205,22 @@ public class SpongeWorldEdit { return this.spongeAdapter; } + @Listener + public void onPlayerItemInteract(InteractItemEvent event, @Root Player spongePlayer) { + if (platform == null) { + return; + } + + if (!platform.isHookingEvents()) return; // We have to be told to catch these events + + WorldEdit we = WorldEdit.getInstance(); + + SpongePlayer player = wrapPlayer(spongePlayer); + if (we.handleRightClick(player)) { + event.setCancelled(true); + } + } + @Listener public void onPlayerInteract(InteractBlockEvent event, @Root Player spongePlayer) { if (platform == null) { @@ -244,26 +261,20 @@ public class SpongeWorldEdit { } } } else if (event instanceof InteractBlockEvent.Secondary) { - if (interactedType != BlockTypes.AIR) { - if (!optLoc.isPresent()) { - return; - } + if (!optLoc.isPresent()) { + return; + } - Location loc = optLoc.get(); - com.sk89q.worldedit.util.Location pos = new com.sk89q.worldedit.util.Location( - world, loc.getX(), loc.getY(), loc.getZ()); + Location loc = optLoc.get(); + com.sk89q.worldedit.util.Location pos = new com.sk89q.worldedit.util.Location( + world, loc.getX(), loc.getY(), loc.getZ()); - if (we.handleBlockRightClick(player, pos)) { - event.setCancelled(true); - } + if (we.handleBlockRightClick(player, pos)) { + event.setCancelled(true); + } - if (we.handleRightClick(player)) { - event.setCancelled(true); - } - } else { - if (we.handleRightClick(player)) { - event.setCancelled(true); - } + if (we.handleRightClick(player)) { + event.setCancelled(true); } } } From 3fd661c513ff0a06b0feb7e4e0c8b5447e2fb9bf Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 8 Jun 2019 11:25:36 -0400 Subject: [PATCH 188/366] Don't attempt to check unloaded world refs. --- .../src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 67d643f89..38d82dc25 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 @@ -310,7 +310,9 @@ public class BukkitWorld extends AbstractWorld { @Override public boolean equals(Object other) { - if (other == null) { + if (worldRef.get() == null) { + return false; + } else if (other == null) { return false; } else if ((other instanceof BukkitWorld)) { return ((BukkitWorld) other).getWorld().equals(getWorld()); From f2f9c266029123869dfd04b1fc9220dbcadccd77 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 9 Jun 2019 00:30:57 -0400 Subject: [PATCH 189/366] Expanded the scope of item brushes (/br apply item, /br paint item). They now additionally take a direction in which the simulated item usage should be facing. Also allow the item parser to parse "hand" and "offhand" as items, to allow platforms with NBT item support return items with NBT (since parsing is a slightly more complex task). --- .../worldedit/blocks/MobSpawnerBlock.java | 7 +- .../com/sk89q/worldedit/blocks/SignBlock.java | 6 +- .../java/com/sk89q/worldedit/WorldEdit.java | 36 +++--- .../worldedit/command/ApplyBrushCommands.java | 20 ++- .../worldedit/command/PaintBrushCommands.java | 20 ++- .../argument/AbstractDirectionConverter.java | 119 ++++++++++++++++++ .../command/argument/DirectionConverter.java | 92 +++----------- .../argument/DirectionVectorConverter.java | 49 ++++++++ .../command/factory/ItemUseFactory.java | 9 +- .../factory/parser/DefaultBlockParser.java | 9 +- .../factory/parser/DefaultItemParser.java | 18 +++ .../platform/PlatformCommandManager.java | 2 + .../worldedit/function/ItemUseFunction.java | 9 +- .../world/registry/LegacyMapper.java | 9 +- 14 files changed, 287 insertions(+), 118 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/AbstractDirectionConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionVectorConverter.java diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java index cde191e64..b68120948 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/MobSpawnerBlock.java @@ -116,7 +116,7 @@ public class MobSpawnerBlock extends BaseBlock { @Override public String getNbtId() { - return "MobSpawner"; + return "minecraft:mob_spawner"; } @Override @@ -154,8 +154,8 @@ public class MobSpawnerBlock extends BaseBlock { Map values = rootTag.getValue(); Tag t = values.get("id"); - if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("MobSpawner")) { - throw new RuntimeException("'MobSpawner' tile entity expected"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) { + throw new RuntimeException(String.format("'%s' tile entity expected", getNbtId())); } CompoundTag spawnDataTag; @@ -169,6 +169,7 @@ public class MobSpawnerBlock extends BaseBlock { throw new InvalidFormatException("No spawn id."); } this.mobType = mobType; + this.spawnData = spawnDataTag; } catch (InvalidFormatException ignored) { throw new RuntimeException("Invalid mob spawner data: no SpawnData and/or no Delay"); } diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java index 4cc0e5bcb..0f1811e13 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SignBlock.java @@ -88,7 +88,7 @@ public class SignBlock extends BaseBlock { @Override public String getNbtId() { - return "Sign"; + return "minecraft:sign"; } @Override @@ -114,8 +114,8 @@ public class SignBlock extends BaseBlock { text = new String[] { EMPTY, EMPTY, EMPTY, EMPTY }; t = values.get("id"); - if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Sign")) { - throw new RuntimeException("'Sign' tile entity expected"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) { + throw new RuntimeException(String.format("'%s' tile entity expected", getNbtId())); } t = values.get("Text1"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index c9e926222..fa60eb72f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -408,15 +408,14 @@ public final class WorldEdit { } /** - * Get the direction vector for a player's direction. May return - * null if a direction could not be found. + * Get the direction vector for a player's direction. * * @param player the player * @param dirStr the direction string * @return a direction vector - * @throws UnknownDirectionException thrown if the direction is not known + * @throws UnknownDirectionException thrown if the direction is not known, or a relative direction is used with null player */ - public BlockVector3 getDirection(Player player, String dirStr) throws UnknownDirectionException { + public BlockVector3 getDirection(@Nullable Player player, String dirStr) throws UnknownDirectionException { dirStr = dirStr.toLowerCase(Locale.ROOT); final Direction dir = getPlayerDirection(player, dirStr); @@ -429,15 +428,14 @@ public final class WorldEdit { } /** - * Get the direction vector for a player's direction. May return - * null if a direction could not be found. + * Get the direction vector for a player's direction. * * @param player the player * @param dirStr the direction string * @return a direction vector - * @throws UnknownDirectionException thrown if the direction is not known + * @throws UnknownDirectionException thrown if the direction is not known, or a relative direction is used with null player */ - public BlockVector3 getDiagonalDirection(Player player, String dirStr) throws UnknownDirectionException { + public BlockVector3 getDiagonalDirection(@Nullable Player player, String dirStr) throws UnknownDirectionException { dirStr = dirStr.toLowerCase(Locale.ROOT); final Direction dir = getPlayerDirection(player, dirStr); @@ -450,15 +448,14 @@ public final class WorldEdit { } /** - * Get the direction vector for a player's direction. May return - * null if a direction could not be found. + * Get the direction vector for a player's direction. * * @param player the player * @param dirStr the direction string * @return a direction enum value - * @throws UnknownDirectionException thrown if the direction is not known + * @throws UnknownDirectionException thrown if the direction is not known, or a relative direction is used with null player */ - private Direction getPlayerDirection(Player player, String dirStr) throws UnknownDirectionException { + private Direction getPlayerDirection(@Nullable Player player, String dirStr) throws UnknownDirectionException { final Direction dir; switch (dirStr.charAt(0)) { @@ -502,19 +499,19 @@ public final class WorldEdit { case 'm': // me case 'f': // forward - dir = player.getCardinalDirection(0); + dir = getDirectionRelative(player, 0); break; case 'b': // back - dir = player.getCardinalDirection(180); + dir = getDirectionRelative(player, 180); break; case 'l': // left - dir = player.getCardinalDirection(-90); + dir = getDirectionRelative(player, -90); break; case 'r': // right - dir = player.getCardinalDirection(90); + dir = getDirectionRelative(player, 90); break; default: @@ -523,6 +520,13 @@ public final class WorldEdit { return dir; } + private Direction getDirectionRelative(Player player, int yawOffset) throws UnknownDirectionException { + if (player != null) { + return player.getCardinalDirection(yawOffset); + } + throw new UnknownDirectionException("Only a player can use relative directions"); + } + /** * Flush a block bag's changes to a player. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java index 25c1dbdc1..67bb630bd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ApplyBrushCommands.java @@ -27,17 +27,22 @@ import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.command.factory.ItemUseFactory; import com.sk89q.worldedit.command.factory.ReplaceFactory; import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.Contextual; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.factory.Apply; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; import com.sk89q.worldedit.regions.factory.RegionFactory; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.format.TextDecoration; import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandManagerService; import org.enginehub.piston.CommandParameters; @@ -53,7 +58,7 @@ import java.util.stream.Collectors; import static java.util.Objects.requireNonNull; import static org.enginehub.piston.part.CommandParts.arg; -@CommandContainer +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class ApplyBrushCommands { private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("shape"), TextComponent.of("The shape of the region")) @@ -111,11 +116,18 @@ public class ApplyBrushCommands { name = "item", desc = "Use an item" ) + @CommandPermissions("worldedit.brush.item") public void item(CommandParameters parameters, Player player, LocalSession localSession, @Arg(desc = "The type of item to use") - BaseItem item) throws WorldEditException { - setApplyBrush(parameters, player, localSession, new ItemUseFactory(item)); + BaseItem item, + @Arg(desc = "The direction in which the item will be applied", def = "up") + @Direction(includeDiagonals = true) + com.sk89q.worldedit.util.Direction direction) throws WorldEditException { + player.print(TextComponent.builder().append("WARNING: ", TextColor.RED, TextDecoration.BOLD) + .append("This brush simulates item usages. Its effects may not work on all platforms, may not be undo-able," + + " and may cause strange interactions with other mods/plugins. Use at your own risk.").build()); + setApplyBrush(parameters, player, localSession, new ItemUseFactory(item, direction)); } @Command( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java index e3c92236b..ea929ec49 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/PaintBrushCommands.java @@ -27,17 +27,22 @@ import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.command.factory.ItemUseFactory; import com.sk89q.worldedit.command.factory.ReplaceFactory; import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; +import com.sk89q.worldedit.command.util.CommandPermissions; +import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.Contextual; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.factory.Paint; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; import com.sk89q.worldedit.regions.factory.RegionFactory; import com.sk89q.worldedit.util.TreeGenerator; -import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.format.TextDecoration; import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandManagerService; import org.enginehub.piston.CommandParameters; @@ -53,7 +58,7 @@ import java.util.stream.Collectors; import static java.util.Objects.requireNonNull; import static org.enginehub.piston.part.CommandParts.arg; -@CommandContainer +@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class PaintBrushCommands { private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("shape"), TextComponent.of("The shape of the region")) @@ -117,11 +122,18 @@ public class PaintBrushCommands { name = "item", desc = "Use an item" ) + @CommandPermissions("worldedit.brush.item") public void item(CommandParameters parameters, Player player, LocalSession localSession, @Arg(desc = "The type of item to use") - BaseItem item) throws WorldEditException { - setPaintBrush(parameters, player, localSession, new ItemUseFactory(item)); + BaseItem item, + @Arg(desc = "The direction in which the item will be applied", def = "up") + @Direction(includeDiagonals = true) + com.sk89q.worldedit.util.Direction direction) throws WorldEditException { + player.print(TextComponent.builder().append("WARNING: ", TextColor.RED, TextDecoration.BOLD) + .append("This brush simulates item usages. Its effects may not work on all platforms, may not be undo-able," + + " and may cause strange interactions with other mods/plugins. Use at your own risk.").build()); + setPaintBrush(parameters, player, localSession, new ItemUseFactory(item, direction)); } @Command( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/AbstractDirectionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/AbstractDirectionConverter.java new file mode 100644 index 000000000..bd2a28067 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/AbstractDirectionConverter.java @@ -0,0 +1,119 @@ +/* + * 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.command.argument; + +import com.google.auto.value.AutoAnnotation; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.sk89q.worldedit.UnknownDirectionException; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.internal.annotation.Direction; +import com.sk89q.worldedit.internal.annotation.MultiDirection; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import javax.annotation.Nullable; +import java.util.List; + +import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; + +public abstract class AbstractDirectionConverter implements ArgumentConverter { + + @AutoAnnotation + private static Direction direction(boolean includeDiagonals) { + return new AutoAnnotation_AbstractDirectionConverter_direction(includeDiagonals); + } + + @AutoAnnotation + private static MultiDirection multiDirection(boolean includeDiagonals) { + return new AutoAnnotation_AbstractDirectionConverter_multiDirection(includeDiagonals); + } + + protected static void register(CommandManager commandManager, AbstractDirectionConverter converter, + Class keyClass, boolean includeDiagonals) { + commandManager.registerConverter( + Key.of(keyClass, direction(includeDiagonals)), + converter + ); + commandManager.registerConverter( + Key.of(keyClass, multiDirection(includeDiagonals)), + CommaSeparatedValuesConverter.wrap(converter) + ); + } + + private static final ImmutableSet ORTHOGONAL = ImmutableSet.of( + "north", "south", "east", "west", "up", "down" + ); + private static final ImmutableSet RELATIVE = ImmutableSet.of( + "me", "forward", "back", "left", "right" + ); + private static final ImmutableSet DIAGONAL = ImmutableSet.of( + "northeast", "northwest", "southeast", "southwest" + ); + + private final WorldEdit worldEdit; + private final boolean includeDiagonals; + private final ImmutableList suggestions; + + protected AbstractDirectionConverter(WorldEdit worldEdit, boolean includeDiagonals) { + this.worldEdit = worldEdit; + this.includeDiagonals = includeDiagonals; + suggestions = ImmutableList.builder() + .addAll(ORTHOGONAL) + .addAll(RELATIVE) + .addAll(includeDiagonals ? DIAGONAL : ImmutableList.of()) + .build(); + } + + @Override + public ConversionResult convert(String argument, InjectedValueAccess context) { + Player player = context.injectedValue(Key.of(Player.class)).orElse(null); + try { + return SuccessfulConversion.fromSingle(convertDirection(argument, player, includeDiagonals)); + } catch (Exception e) { + return FailedConversion.from(e); + } + } + + protected abstract D convertDirection(String argument, @Nullable Player player, boolean includeDiagonals) throws UnknownDirectionException; + + @Override + public Component describeAcceptableArguments() { + return TextComponent.of("`me` to use facing direction, or any " + + (includeDiagonals ? "direction" : "non-diagonal direction")); + } + + @Override + public List getSuggestions(String input) { + return limitByPrefix(suggestions.stream(), input); + } + + protected WorldEdit getWorldEdit() { + return worldEdit; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java index 78d702aa9..22e0b2fbe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java @@ -19,101 +19,37 @@ package com.sk89q.worldedit.command.argument; -import com.google.auto.value.AutoAnnotation; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; import com.sk89q.worldedit.UnknownDirectionException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.internal.annotation.Direction; -import com.sk89q.worldedit.internal.annotation.MultiDirection; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.Direction; import org.enginehub.piston.CommandManager; -import org.enginehub.piston.converter.ArgumentConverter; -import org.enginehub.piston.converter.ConversionResult; -import org.enginehub.piston.converter.FailedConversion; -import org.enginehub.piston.converter.SuccessfulConversion; -import org.enginehub.piston.inject.InjectedValueAccess; -import org.enginehub.piston.inject.Key; -import java.util.List; +import javax.annotation.Nullable; +import java.util.Optional; -import static java.util.stream.Collectors.toList; -import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix; +public final class DirectionConverter extends AbstractDirectionConverter { -public class DirectionConverter implements ArgumentConverter { - - @AutoAnnotation - private static Direction direction(boolean includeDiagonals) { - return new AutoAnnotation_DirectionConverter_direction(includeDiagonals); - } - - @AutoAnnotation - private static MultiDirection multiDirection(boolean includeDiagonals) { - return new AutoAnnotation_DirectionConverter_multiDirection(includeDiagonals); + private DirectionConverter(WorldEdit worldEdit, boolean includeDiagonals) { + super(worldEdit, includeDiagonals); } public static void register(WorldEdit worldEdit, CommandManager commandManager) { for (boolean includeDiagonals : new boolean[] { false, true }) { DirectionConverter directionConverter = new DirectionConverter(worldEdit, includeDiagonals); - commandManager.registerConverter( - Key.of(BlockVector3.class, direction(includeDiagonals)), - directionConverter - ); - commandManager.registerConverter( - Key.of(BlockVector3.class, multiDirection(includeDiagonals)), - CommaSeparatedValuesConverter.wrap(directionConverter) - ); - } - } - - private static final ImmutableSet NON_DIAGONALS = ImmutableSet.of( - "north", "south", "east", "west", "up", "down" - ); - private static final ImmutableSet RELATIVE = ImmutableSet.of( - "me", "forward", "back", "left", "right" - ); - private static final ImmutableSet DIAGONALS = ImmutableSet.of( - "northeast", "northwest", "southeast", "southwest" - ); - - private final WorldEdit worldEdit; - private final boolean includeDiagonals; - private final ImmutableList suggestions; - - private DirectionConverter(WorldEdit worldEdit, boolean includeDiagonals) { - this.worldEdit = worldEdit; - this.includeDiagonals = includeDiagonals; - suggestions = ImmutableList.builder() - .addAll(NON_DIAGONALS) - .addAll(RELATIVE) - .addAll(includeDiagonals ? DIAGONALS : ImmutableList.of()) - .build(); - } - - @Override - public ConversionResult convert(String argument, InjectedValueAccess context) { - Player player = context.injectedValue(Key.of(Player.class)) - .orElseThrow(() -> new IllegalStateException("No player available")); - try { - return SuccessfulConversion.fromSingle(includeDiagonals - ? worldEdit.getDiagonalDirection(player, argument) - : worldEdit.getDirection(player, argument)); - } catch (Exception e) { - return FailedConversion.from(e); + register(commandManager, directionConverter, Direction.class, includeDiagonals); } } @Override - public Component describeAcceptableArguments() { - return TextComponent.of("`me` to use facing direction, or any " - + (includeDiagonals ? "direction" : "non-diagonal direction")); + protected Direction convertDirection(String argument, @Nullable Player player, boolean includeDiagonals) throws UnknownDirectionException { + final BlockVector3 vec = includeDiagonals + ? getWorldEdit().getDiagonalDirection(player, argument) + : getWorldEdit().getDirection(player, argument); + return Optional.ofNullable(Direction.findClosest(vec.toVector3(), Direction.Flag.ALL)) + .orElseThrow(() -> new UnknownDirectionException(argument)); } - @Override - public List getSuggestions(String input) { - return limitByPrefix(suggestions.stream(), input); - } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionVectorConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionVectorConverter.java new file mode 100644 index 000000000..1295fbceb --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionVectorConverter.java @@ -0,0 +1,49 @@ +/* + * 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.command.argument; + +import com.sk89q.worldedit.UnknownDirectionException; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.math.BlockVector3; +import org.enginehub.piston.CommandManager; + +import javax.annotation.Nullable; + +public final class DirectionVectorConverter extends AbstractDirectionConverter { + + private DirectionVectorConverter(WorldEdit worldEdit, boolean includeDiagonals) { + super(worldEdit, includeDiagonals); + } + + public static void register(WorldEdit worldEdit, CommandManager commandManager) { + for (boolean includeDiagonals : new boolean[] { false, true }) { + DirectionVectorConverter directionConverter = new DirectionVectorConverter(worldEdit, includeDiagonals); + register(commandManager, directionConverter, BlockVector3.class, includeDiagonals); + } + } + + @Override + protected BlockVector3 convertDirection(String argument, @Nullable Player player, boolean includeDiagonals) throws UnknownDirectionException { + return includeDiagonals + ? getWorldEdit().getDiagonalDirection(player, argument) + : getWorldEdit().getDirection(player, argument); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java index a099a78a1..7ad8866c3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/ItemUseFactory.java @@ -25,19 +25,26 @@ import com.sk89q.worldedit.function.ItemUseFunction; import com.sk89q.worldedit.function.Contextual; import com.sk89q.worldedit.function.EditContext; import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.World; public final class ItemUseFactory implements Contextual { private final BaseItem item; + private final Direction dir; public ItemUseFactory(BaseItem item) { + this(item, Direction.UP); + } + + public ItemUseFactory(BaseItem item, Direction dir) { this.item = item; + this.dir = dir; } @Override public RegionFunction createFromContext(EditContext input) { World world = ((EditSession) input.getDestination()).getWorld(); - return new ItemUseFunction(world, item); + return new ItemUseFunction(world, item, dir); } @Override 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 9f4402715..55a9089b0 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 @@ -41,6 +41,7 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockCategory; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -170,9 +171,9 @@ public class DefaultBlockParser extends InputParser { Property propertyKey = (Property) type.getPropertyMap().get(parts[0]); if (propertyKey == null) { if (context.getActor() != null) { - throw new NoMatchException("Unknown property " + parts[0] + " for block " + type.getName()); + throw new NoMatchException("Unknown property " + parts[0] + " for block " + type.getId()); } else { - WorldEdit.logger.warn("Unknown property " + parts[0] + " for block " + type.getName()); + WorldEdit.logger.warn("Unknown property " + parts[0] + " for block " + type.getId()); } return Maps.newHashMap(); } @@ -345,7 +346,9 @@ public class DefaultBlockParser extends InputParser { } } - if (blockType == BlockTypes.SIGN || blockType == BlockTypes.WALL_SIGN) { + final BlockCategory signCategory = BlockCategory.REGISTRY.get("minecraft:signs"); + if (blockType == BlockTypes.SIGN || blockType == BlockTypes.WALL_SIGN + || signCategory != null && signCategory.contains(blockType)) { // Allow special sign text syntax String[] text = new String[4]; text[0] = blockAndExtraData.length > 1 ? blockAndExtraData[1] : ""; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java index 450538f28..631fed2dd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/DefaultItemParser.java @@ -21,10 +21,14 @@ package com.sk89q.worldedit.extension.factory.parser; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.registry.InputParser; +import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.registry.LegacyMapper; @@ -65,6 +69,12 @@ public class DefaultItemParser extends InputParser { } } + if ("hand".equalsIgnoreCase(input)) { + return getItemInHand(context.requireActor(), HandSide.MAIN_HAND); + } else if ("offhand".equalsIgnoreCase(input)) { + return getItemInHand(context.requireActor(), HandSide.OFF_HAND); + } + if (item == null) { ItemType type = ItemTypes.get(input.toLowerCase(Locale.ROOT)); if (type != null) { @@ -79,4 +89,12 @@ public class DefaultItemParser extends InputParser { } } + private BaseItemStack getItemInHand(Actor actor, HandSide handSide) throws InputParseException { + if (actor instanceof Player) { + return ((Player) actor).getItemInHand(handSide); + } else { + throw new InputParseException("The user is not a player!"); + } + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 2de667d08..3086613ec 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -72,6 +72,7 @@ import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.argument.BooleanConverter; import com.sk89q.worldedit.command.argument.CommaSeparatedValuesConverter; import com.sk89q.worldedit.command.argument.DirectionConverter; +import com.sk89q.worldedit.command.argument.DirectionVectorConverter; import com.sk89q.worldedit.command.argument.EntityRemoverConverter; import com.sk89q.worldedit.command.argument.EnumConverter; import com.sk89q.worldedit.command.argument.FactoryConverter; @@ -200,6 +201,7 @@ public final class PlatformCommandManager { } private void registerArgumentConverters() { + DirectionVectorConverter.register(worldEdit, commandManager); DirectionConverter.register(worldEdit, commandManager); FactoryConverter.register(worldEdit, commandManager); for (int count = 2; count <= 3; count++) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java index 4e439f0c3..905ccd3e6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/ItemUseFunction.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.function; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; -import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.World; @@ -29,14 +28,20 @@ import com.sk89q.worldedit.world.World; public final class ItemUseFunction implements RegionFunction { private final World world; private final BaseItem item; + private final Direction dir; public ItemUseFunction(World world, BaseItem item) { + this(world, item, Direction.UP); + } + + public ItemUseFunction(World world, BaseItem item, Direction dir) { this.world = world; this.item = item; + this.dir = dir; } @Override public boolean apply(BlockVector3 position) throws WorldEditException { - return world.useItem(position, item, Direction.UP); + return world.useItem(position, item, dir); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java index d12503f19..e48444094 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/LegacyMapper.java @@ -93,15 +93,16 @@ public final class LegacyMapper { for (Map.Entry blockEntry : dataFile.blocks.entrySet()) { String id = blockEntry.getKey(); - blockEntries.put(id, blockEntry.getValue()); + final String value = blockEntry.getValue(); + blockEntries.put(id, value); try { - BlockState state = WorldEdit.getInstance().getBlockFactory().parseFromInput(blockEntry.getValue(), parserContext).toImmutableState(); + BlockState state = WorldEdit.getInstance().getBlockFactory().parseFromInput(value, parserContext).toImmutableState(); blockToStringMap.put(state, id); stringToBlockMap.put(id, state); } catch (InputParseException e) { boolean fixed = false; if (fixer != null) { - String newEntry = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, blockEntry.getValue(), 1631); + String newEntry = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, value, 1631); try { BlockState state = WorldEdit.getInstance().getBlockFactory().parseFromInput(newEntry, parserContext).toImmutableState(); blockToStringMap.put(state, id); @@ -111,7 +112,7 @@ public final class LegacyMapper { } } if (!fixed) { - log.warn("Unknown block: " + blockEntry.getValue()); + log.warn("Unknown block: " + value); } } } From c361da11f149134391cc974f994d83163dfb08e0 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 9 Jun 2019 11:18:10 -0400 Subject: [PATCH 190/366] Various fixes and improvements for Forge WE 1.13. --- .../sk89q/worldedit/forge/ForgeAdapter.java | 15 +++++- .../forge/ForgeBlockCategoryRegistry.java | 46 ++++++++++++++++++ .../worldedit/forge/ForgeBlockRegistry.java | 3 +- .../sk89q/worldedit/forge/ForgeDataFixer.java | 3 +- .../forge/ForgeItemCategoryRegistry.java | 46 ++++++++++++++++++ .../worldedit/forge/ForgeItemRegistry.java | 14 +++++- .../sk89q/worldedit/forge/ForgePlayer.java | 42 ++++++++++++---- .../worldedit/forge/ForgeRegistries.java | 14 ++++++ .../com/sk89q/worldedit/forge/ForgeWorld.java | 38 ++++++++------- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 39 ++++----------- .../worldedit/forge/WorldEditFakePlayer.java | 4 ++ .../net/handler/InternalPacketHandler.java | 16 +++---- .../forge/net/handler/PacketHandlerUtil.java | 48 +++++++++++++++++++ .../forge/net/handler/WECUIPacketHandler.java | 11 ++--- 14 files changed, 263 insertions(+), 76 deletions(-) create mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java create mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java create mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java index 164ac65cf..bc6448636 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.forge; import com.google.common.collect.ImmutableList; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -210,11 +211,23 @@ public final class ForgeAdapter { if (baseItemStack.getNbtData() != null) { forgeCompound = NBTConverter.toNative(baseItemStack.getNbtData()); } - return new ItemStack(adapt(baseItemStack.getType()), baseItemStack.getAmount(), forgeCompound); + final ItemStack itemStack = new ItemStack(adapt(baseItemStack.getType()), baseItemStack.getAmount()); + itemStack.setTag(forgeCompound); + return itemStack; } public static BaseItemStack adapt(ItemStack itemStack) { CompoundTag tag = NBTConverter.fromNative(itemStack.serializeNBT()); + if (tag.getValue().isEmpty()) { + tag = null; + } else { + final Tag tagTag = tag.getValue().get("tag"); + if (tagTag instanceof CompoundTag) { + tag = ((CompoundTag) tagTag); + } else { + tag = null; + } + } return new BaseItemStack(adapt(itemStack.getItem()), tag, itemStack.getCount()); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java new file mode 100644 index 000000000..85fdc4fea --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java @@ -0,0 +1,46 @@ +/* + * 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.forge; + +import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; +import net.minecraft.tags.BlockTags; +import net.minecraft.tags.Tag; +import net.minecraft.util.ResourceLocation; + +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class ForgeBlockCategoryRegistry implements BlockCategoryRegistry { + @Override + public Set getCategorisedByName(String category) { + return Optional.ofNullable(BlockTags.getCollection().get(new ResourceLocation(category))) + .map(Tag::getAllElements).orElse(Collections.emptySet()) + .stream().map(ForgeAdapter::adapt).collect(Collectors.toSet()); + } + + @Override + public Set getAll(Category category) { + return getCategorisedByName(category.getId()); + } +} diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java index 91c0b4cc8..e918d3e52 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.world.registry.BundledBlockRegistry; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.state.IProperty; +import net.minecraftforge.fml.loading.FMLLoader; import java.util.Collection; import java.util.HashMap; @@ -42,7 +43,7 @@ public class ForgeBlockRegistry extends BundledBlockRegistry { @Override public String getName(BlockType blockType) { Block block = ForgeAdapter.adapt(blockType); - if (block != null) { + if (block != null && FMLLoader.getDist().isClient()) { return block.getNameTextComponent().getFormattedText(); } else { return super.getName(blockType); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java index 30e5ae74f..075e70bde 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java @@ -212,13 +212,14 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor INSTANCE = this; registerConverters(); registerInspectors(); + this.fixer = new WrappedDataFixer(DataFixesManager.getDataFixer()); } // Called after fixers are built and ready for FIXING @Override public DataFixer build(final Executor executor) { - return this.fixer = new WrappedDataFixer(DataFixesManager.getDataFixer()); + return fixer; } private class WrappedDataFixer implements DataFixer { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java new file mode 100644 index 000000000..a12fb10c3 --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java @@ -0,0 +1,46 @@ +/* + * 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.forge; + +import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; +import net.minecraft.tags.ItemTags; +import net.minecraft.tags.Tag; +import net.minecraft.util.ResourceLocation; + +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class ForgeItemCategoryRegistry implements ItemCategoryRegistry { + @Override + public Set getCategorisedByName(String category) { + return Optional.ofNullable(ItemTags.getCollection().get(new ResourceLocation(category))) + .map(Tag::getAllElements).orElse(Collections.emptySet()) + .stream().map(ForgeAdapter::adapt).collect(Collectors.toSet()); + } + + @Override + public Set getAll(Category category) { + return getCategorisedByName(category.getId()); + } +} diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java index 502c646fc..998027802 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemRegistry.java @@ -21,6 +21,11 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.BundledItemRegistry; +import net.minecraft.client.resources.I18n; +import net.minecraft.item.Item; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.loading.FMLLoader; +import net.minecraftforge.registries.RegistryManager; import javax.annotation.Nullable; @@ -29,6 +34,13 @@ public class ForgeItemRegistry extends BundledItemRegistry { @Nullable @Override public String getName(ItemType itemType) { - return super.getName(itemType); // TODO + if (FMLLoader.getDist().isClient()) { + final Item item = RegistryManager.ACTIVE.getRegistry(Item.class) + .getValue(ResourceLocation.tryCreate(itemType.getId())); + if (item != null) { + return I18n.format(item.getTranslationKey()); + } + } + return super.getName(itemType); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index c478934c5..3d6335e46 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.forge; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; @@ -33,12 +34,16 @@ import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; import io.netty.buffer.Unpooled; +import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; +import net.minecraft.network.play.server.SPacketBlockChange; import net.minecraft.network.play.server.SPacketCustomPayload; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.util.EnumHand; @@ -48,12 +53,14 @@ import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextFormatting; +import java.io.IOException; import java.util.UUID; import javax.annotation.Nullable; public class ForgePlayer extends AbstractPlayerActor { + private static final int STRUCTURE_BLOCK_PACKET_ID = 7; private final EntityPlayerMP player; protected ForgePlayer(EntityPlayerMP player) { @@ -183,18 +190,35 @@ public class ForgePlayer extends AbstractPlayerActor { @Override public > void sendFakeBlock(BlockVector3 pos, B block) { + World world = getWorld(); + if (!(world instanceof ForgeWorld)) { + return; + } BlockPos loc = ForgeAdapter.toBlockPos(pos); if (block == null) { - // TODO -// player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData()); + final SPacketBlockChange packetOut = new SPacketBlockChange(((ForgeWorld) world).getWorld(), loc); + player.connection.sendPacket(packetOut); } else { - // TODO -// player.sendBlockChange(loc, BukkitAdapter.adapt(block)); - if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) { - player.connection.sendPacket(new SPacketUpdateTileEntity( - new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), 7, - NBTConverter.toNative(((BaseBlock) block).getNbtData())) - ); + final SPacketBlockChange packetOut = new SPacketBlockChange(); + PacketBuffer buf = new PacketBuffer(Unpooled.buffer()); + buf.writeBlockPos(loc); + buf.writeVarInt(Block.getStateId(ForgeAdapter.adapt(block.toImmutableState()))); + try { + packetOut.readPacketData(buf); + } catch (IOException e) { + return; + } + player.connection.sendPacket(packetOut); + if (block instanceof BaseBlock && block.getBlockType().equals(BlockTypes.STRUCTURE_BLOCK)) { + final BaseBlock baseBlock = (BaseBlock) block; + final CompoundTag nbtData = baseBlock.getNbtData(); + if (nbtData != null) { + player.connection.sendPacket(new SPacketUpdateTileEntity( + new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), + STRUCTURE_BLOCK_PACKET_ID, + NBTConverter.toNative(nbtData)) + ); + } } } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeRegistries.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeRegistries.java index 27b6f36df..ee3d3203f 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeRegistries.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeRegistries.java @@ -20,8 +20,10 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.world.registry.BiomeRegistry; +import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; import com.sk89q.worldedit.world.registry.BlockRegistry; import com.sk89q.worldedit.world.registry.BundledRegistries; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; import com.sk89q.worldedit.world.registry.ItemRegistry; /** @@ -33,6 +35,8 @@ class ForgeRegistries extends BundledRegistries { private final BlockRegistry blockRegistry = new ForgeBlockRegistry(); private final BiomeRegistry biomeRegistry = new ForgeBiomeRegistry(); private final ItemRegistry itemRegistry = new ForgeItemRegistry(); + private final BlockCategoryRegistry blockCategoryRegistry = new ForgeBlockCategoryRegistry(); + private final ItemCategoryRegistry itemCategoryRegistry = new ForgeItemCategoryRegistry(); @Override public BlockRegistry getBlockRegistry() { @@ -49,6 +53,16 @@ class ForgeRegistries extends BundledRegistries { return itemRegistry; } + @Override + public BlockCategoryRegistry getBlockCategoryRegistry() { + return blockCategoryRegistry; + } + + @Override + public ItemCategoryRegistry getItemCategoryRegistry() { + return itemCategoryRegistry; + } + /** * Get a static instance. * diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index c5b5f8fba..4b6c8d6a5 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -60,8 +60,11 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; @@ -243,25 +246,26 @@ public class ForgeWorld extends AbstractWorld { @Override public boolean useItem(BlockVector3 position, BaseItem item, Direction face) { - Item nativeItem = ForgeAdapter.adapt(item.getType()); - ItemStack stack; - if (item.getNbtData() == null) { - stack = new ItemStack(nativeItem, 1); - } else { - stack = new ItemStack(nativeItem, 1, NBTConverter.toNative(item.getNbtData())); - } + ItemStack stack = ForgeAdapter.adapt(new BaseItemStack(item.getType(), item.getNbtData(), 1)); World world = getWorld(); - ItemUseContext itemUseContext = new ItemUseContext( - new WorldEditFakePlayer((WorldServer) world), - stack, - ForgeAdapter.toBlockPos(position), - ForgeAdapter.adapt(face), - 0f, - 0f, - 0f - ); + final WorldEditFakePlayer fakePlayer = new WorldEditFakePlayer((WorldServer) world); + fakePlayer.setHeldItem(EnumHand.MAIN_HAND, stack); + fakePlayer.setLocationAndAngles(position.getBlockX(), position.getBlockY(), position.getBlockZ(), + (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); + final BlockPos blockPos = ForgeAdapter.toBlockPos(position); + final EnumFacing enumFacing = ForgeAdapter.adapt(face); + ItemUseContext itemUseContext = new ItemUseContext(fakePlayer, stack, blockPos, enumFacing, blockPos.getX(), blockPos.getY(), blockPos.getZ()); EnumActionResult used = stack.onItemUse(itemUseContext); - return used != EnumActionResult.FAIL; + if (used != EnumActionResult.SUCCESS) { + // try activating the block + if (getWorld().getBlockState(blockPos).onBlockActivated(world, blockPos, fakePlayer, EnumHand.MAIN_HAND, + enumFacing, blockPos.getX(), blockPos.getY(), blockPos.getZ())) { + used = EnumActionResult.SUCCESS; + } else { + used = stack.getItem().onItemRightClick(world, fakePlayer, EnumHand.MAIN_HAND).getType(); + } + } + return used == EnumActionResult.SUCCESS; } @Override diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index aef34005a..897cebe16 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -46,6 +46,7 @@ import net.minecraft.command.CommandSource; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.tags.BlockTags; import net.minecraft.tags.ItemTags; +import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; @@ -105,7 +106,6 @@ public class ForgeWorldEdit { IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); modBus.addListener(this::init); - modBus.addListener(this::load); MinecraftForge.EVENT_BUS.register(ThreadSafeCache.getInstance()); MinecraftForge.EVENT_BUS.register(this); @@ -131,24 +131,6 @@ public class ForgeWorldEdit { LOGGER.info("WorldEdit for Forge (version " + getInternalVersion() + ") is loaded"); } - private void load(FMLLoadCompleteEvent event) { - if (FMLLoader.getDist() == Dist.CLIENT) { - // we want to setup platform before we hit the main menu - // but this event is async -- so we must delay until the first game loop: - Minecraft.getInstance().addScheduledTask(this::setupPlatform); - } - } - - @SubscribeEvent - public void serverAboutToStart(FMLServerAboutToStartEvent event) { - if (this.platform != null) { - LOGGER.warn("FMLServerStartingEvent occurred when FMLServerStoppingEvent hasn't"); - WorldEdit.getInstance().getPlatformManager().unregister(platform); - } - - setupPlatform(); - } - private void setupPlatform() { this.platform = new ForgePlatform(this); @@ -159,11 +141,6 @@ public class ForgeWorldEdit { // } else { this.provider = new ForgePermissionsProvider.VanillaPermissionsProvider(platform); // } - - setupRegistries(); - - config = new ForgeConfiguration(this); - config.load(); } private void setupRegistries() { @@ -214,6 +191,11 @@ public class ForgeWorldEdit { @SubscribeEvent public void serverStarted(FMLServerStartedEvent event) { + setupPlatform(); + setupRegistries(); + + config = new ForgeConfiguration(this); + config.load(); WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); } @@ -228,7 +210,7 @@ public class ForgeWorldEdit { if (event.getWorld().isRemote && event instanceof LeftClickEmpty) { // catch LCE, pass it to server - InternalPacketHandler.HANDLER.sendToServer(new LeftClickAirEventMessage()); + InternalPacketHandler.getHandler().sendToServer(new LeftClickAirEventMessage()); return; } @@ -239,7 +221,7 @@ public class ForgeWorldEdit { event instanceof PlayerInteractEvent.RightClickBlock && ((PlayerInteractEvent.RightClickBlock) event) .getUseItem() == Event.Result.DENY; - if (isLeftDeny || isRightDeny || event.getEntity().world.isRemote) { + if (isLeftDeny || isRightDeny || event.getEntity().world.isRemote || event.getHand() == EnumHand.OFF_HAND) { return; } @@ -248,10 +230,7 @@ public class ForgeWorldEdit { ForgeWorld world = getWorld(event.getEntityPlayer().world); if (event instanceof PlayerInteractEvent.LeftClickEmpty) { - if (we.handleArmSwing(player)) { - // this event cannot be canceled - // event.setCanceled(true); - } + we.handleArmSwing(player); // this event cannot be canceled } else if (event instanceof PlayerInteractEvent.LeftClickBlock) { Location pos = new Location(world, event.getPos().getX(), event.getPos().getY(), event.getPos().getZ()); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java index 35d6c8381..153c602f1 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java @@ -33,4 +33,8 @@ public class WorldEditFakePlayer extends FakePlayer { super(world, FAKE_GAME_PROFILE); } + @Override + public boolean canEat(boolean ignoreHunger) { + return true; + } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java index 17b81a852..aadb6c083 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/InternalPacketHandler.java @@ -19,20 +19,14 @@ package com.sk89q.worldedit.forge.net.handler; -import com.sk89q.worldedit.forge.ForgeWorldEdit; import com.sk89q.worldedit.forge.net.packet.LeftClickAirEventMessage; import com.sk89q.worldedit.forge.net.packet.LeftClickAirEventMessage.Handler; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.network.NetworkRegistry.ChannelBuilder; import net.minecraftforge.fml.network.simple.SimpleChannel; public final class InternalPacketHandler { - private static final String PROTOCOL_VERSION = Integer.toString(1); - public static SimpleChannel HANDLER = ChannelBuilder - .named(new ResourceLocation(ForgeWorldEdit.MOD_ID, "internal")) - .clientAcceptedVersions(PROTOCOL_VERSION::equals) - .serverAcceptedVersions(PROTOCOL_VERSION::equals) - .networkProtocolVersion(() -> PROTOCOL_VERSION) + private static final int PROTOCOL_VERSION = 1; + private static SimpleChannel HANDLER = PacketHandlerUtil + .buildLenientHandler("internal", PROTOCOL_VERSION) .simpleChannel(); private InternalPacketHandler() { @@ -42,4 +36,8 @@ public final class InternalPacketHandler { HANDLER.registerMessage(0, LeftClickAirEventMessage.class, LeftClickAirEventMessage::encode, LeftClickAirEventMessage::decode, Handler::handle); } + + public static SimpleChannel getHandler() { + return HANDLER; + } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java new file mode 100644 index 000000000..4295047a9 --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java @@ -0,0 +1,48 @@ +/* + * 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.forge.net.handler; + +import com.sk89q.worldedit.forge.ForgeWorldEdit; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.network.NetworkRegistry; + +import java.util.function.Predicate; + +final class PacketHandlerUtil { + private PacketHandlerUtil() { + } + + static NetworkRegistry.ChannelBuilder buildLenientHandler(String id, int protocolVersion) { + final String verStr = Integer.toString(protocolVersion); + final Predicate validator = validateLenient(verStr); + return NetworkRegistry.ChannelBuilder + .named(new ResourceLocation(ForgeWorldEdit.MOD_ID, id)) + .clientAcceptedVersions(validator) + .serverAcceptedVersions(validator) + .networkProtocolVersion(() -> verStr); + } + + private static Predicate validateLenient(String protocolVersion) { + return remoteVersion -> + protocolVersion.equals(remoteVersion) + || NetworkRegistry.ABSENT.equals(remoteVersion) + || NetworkRegistry.ACCEPTVANILLA.equals(remoteVersion); + } +} diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java index 5273887ea..d726a0eb1 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java @@ -29,7 +29,6 @@ import net.minecraft.network.play.server.SPacketCustomPayload; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.network.NetworkEvent.ClientCustomPayloadEvent; import net.minecraftforge.fml.network.NetworkEvent.ServerCustomPayloadEvent; -import net.minecraftforge.fml.network.NetworkRegistry.ChannelBuilder; import net.minecraftforge.fml.network.event.EventNetworkChannel; import java.nio.charset.Charset; @@ -41,13 +40,11 @@ public final class WECUIPacketHandler { } public static final Charset UTF_8_CHARSET = Charset.forName("UTF-8"); - private static final String PROTOCOL_VERSION = Integer.toString(1); - public static EventNetworkChannel HANDLER = ChannelBuilder - .named(new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL)) - .clientAcceptedVersions(PROTOCOL_VERSION::equals) - .serverAcceptedVersions(PROTOCOL_VERSION::equals) - .networkProtocolVersion(() -> PROTOCOL_VERSION) + private static final int PROTOCOL_VERSION = 1; + private static EventNetworkChannel HANDLER = PacketHandlerUtil + .buildLenientHandler(ForgeWorldEdit.CUI_PLUGIN_CHANNEL, PROTOCOL_VERSION) .eventNetworkChannel(); + public static void init() { HANDLER.addListener(WECUIPacketHandler::onPacketData); From 214af8a5358146793c918fc51007c66f4cf929aa Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Tue, 11 Jun 2019 21:15:35 +1000 Subject: [PATCH 191/366] Update changelog --- CHANGELOG.txt | 91 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 0eb07256a..c49cdaaca 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,13 +1,84 @@ -7.0-beta-1 -- Added support for 1.13. -- Removed support for all prior versions. -- Added a basic server-only GUI for editing. //drawsel to enable/disable. Requires creative. -- Added a tag mask, ##minecraft:tag_name. -- Added Sponge Schematic Format to replace MCEdit Schematics. -- Added a compatibility layer for old schematics. -- Rewrote the block parser, now uses official Minecraft format, minecraft:snow[layers=7] -- Removed deprecated code. -- Many more major changes! (Read this blog post for more details https://blog.me4502.com/updating-worldedit-to-minecraft-113.html) +7.0.0 +See https://matthewmiller.dev/blog/introducing-worldedit-7/ for a friendlier explanation of some new features + +- Added support for 1.13 and higher versions, and removed support for earlier +- Use the official Minecraft format for entering blocks, `minecraft:oak_sign[rotation=7]` +- Massively improved the //help command +- Added a "##tag" pattern to set random blocks from the tag +- Fixed long-range build tool +- Fixed generation of hollow shapes +- Improve general performance +- Fixed some issues with the fuzzy blocks parser +- Fixed the clipboard brush description not showing some flags +- Added offset to ClipboardPattern, "//set #clipboard@-1,0,1" +- Added a "##*tag" pattern that behaves similarly to "##tag" but sets all BlockStates +- Added methods to set states and types of blocks independently, explained in this blog post +- Fixed an issue with legacy block IDs returning the wrong stair shapes +- Added a biome registry to make biomes more modern and stable +- Fixed a few issues where WorldEdit will fail to load on versions that it hasn't been updated for yet +- Use radius for the clipboard brush rather than diameter +- Fixed some utility commands missing radius checks +- Re-add mask support to the smooth command, to replace natural smoothing +- Fixed some positional issues with craftscripts +- Fixed a few issues with using hand/offhand/pos as block parser targets +- Improved expression timeouts to reduce overhead +- Improved entity conversions with legacy schematics +- Fixed a few issues with "//schem save" and certain filesystem setups +- Fixed a few issues with the forest commands +- Added -f flag to //count to allow fuzzy inputs +- Fixed TrueZip region stores +- Partial support for CubicChunks, only upwards directions +- Update many messages throughout the plugin to use new text features of Minecraft +- Added biome and entity storing to the Sponge schematics +- Improve TileEntity conversions for legacy schematics +- Fixed "//size" on clipboards +- Fixed some locale related issues that could occur in some specific circumstances +- Switched to a new command system, to allow more modern features such as completions +- Fixed an issue with invalid blocks being fuzzy compared +- Added proper world conversions for files being loaded with "//restore" +- Fixed other small miscellaneous issues +- Remove the final stage committer from the MultiStage reorder mode, as it was unnecessary +- Added /we report, and move the reporting system into WorldEdit +- Update draw.js, roof.js, and maze.js +- Allow the 'leave-id' parameter of //move to be a pattern rather than just a block +- Modularised masks and patterns, allowing plugins to register their own +- Minor improvements to the server side CUI +- Cleaned up the fuzzy blocks system +- Improved the error shown when WorldEdit doesn't support the platform +- Provide better caching with LastAccessExtent +- Allow biome changes to be undone +- Workaround for a Spigot bug where it incorrectly sends a few commands to the client for tab completion despite permissions +- Fixed issue where blockbags were checked for items when a block didn't need to change +- Added a "fast" mode for reordering blocks. In the future this will be the default as it is much faster, it just needs more testing. + - Reordering blocks is what allows edits to not break signs off walls, or doors off the ground. + - To enable, run //reorder fast + - To disable, run //reorder multi + - This affects all edits + - You can disable reordering entirely if you know what you're doing, with //reorder none +- Fixed a bug with Entity resolution +- More gracefully handle errors if the world's palette is corrupt +- Made BlockType lazily-loaded +- Properly rotate blocks. This should be fairly future resilient and work with mods +- Added a configurable timeout to expression evaluation +- Edits are now batched by chunks and ordered by region files, improving performance +- Improved the API around flushing edit sessions +- Refactored the vector system to prevent bugs caused by confusion, and improve performance due to less memory allocation +- Added a debug option to help developers find places they've forgotten to flush sessions that require flushing +- Added partial diagonal direction support back to some commands (Was removed in WorldEdit 6) +- Added //drawsel, a Server-Side WorldEditCUI for small cuboid selections (< 32x32x32) +- Rewrote the block parser, now properly handles Minecraft 1.13 names (See this blog post for more information) +- Switched to the Sponge Schematic format, as the MCEdit Schematic Format does not work in 1.13 + - Old schematics will be loaded and converted as best as possible +- Major improvements to the API (See this blog post for more information) +- Removal of all old deprecated code +- Added /tracemask, to set masks used for brush tracing +- Added suggestions to almost all commands +- Allowed plugins to register their own masks and patterns +- Removed command requirement for CUI +- Added a permission node to set NBT data, allowing servers to disallow copying full chests etc +- Made a few paged commands use -p for pages +- Fixed //restore not working for very old chunks +- Massively expanded the capabilities of apply and paint item brushes 6.1 - Added support for Spigot for MC 1.8.3 to 1.8.6. From 84eb4b1aab7289d0c7f1b7ca576c33bc230f4862 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Tue, 11 Jun 2019 21:36:19 +1000 Subject: [PATCH 192/366] Bump to 7.0.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 839562495..a0becdc7a 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ println """ allprojects { group = 'com.sk89q.worldedit' - version = '7.0.0-SNAPSHOT' + version = '7.0.0' } if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost" From f89bc3a64882c7a2ad69c41c624be769ea89c48d Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Tue, 11 Jun 2019 21:38:53 +1000 Subject: [PATCH 193/366] 7.0.1 Snapshots --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index a0becdc7a..80c9e31f2 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ println """ allprojects { group = 'com.sk89q.worldedit' - version = '7.0.0' + version = '7.0.1-SNAPSHOT' } if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost" From 026bfeed08b3dececff6973958c9719eb0c2eec8 Mon Sep 17 00:00:00 2001 From: Wyatt Childers Date: Mon, 10 Jun 2019 23:24:53 -0400 Subject: [PATCH 194/366] Improved usage of the naturalize command over large areas This change fixes the block count report, and also makes naturalize act more like a "//replace dirt grass" where we only attempt block changes if the block is not already what we're looking for. --- .../worldedit/function/block/Naturalizer.java | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java index c4c72951e..2242e83a7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/Naturalizer.java @@ -27,6 +27,7 @@ import com.sk89q.worldedit.function.LayerFunction; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; /** @@ -65,21 +66,35 @@ public class Naturalizer implements LayerFunction { return mask.test(position); } + private BlockState getTargetBlock(int depth) { + switch (depth) { + case 0: + return BlockTypes.GRASS_BLOCK.getDefaultState(); + case 1: + case 2: + case 3: + return BlockTypes.DIRT.getDefaultState(); + default: + return BlockTypes.STONE.getDefaultState(); + } + } + + private boolean naturalize(BlockVector3 position, int depth) throws WorldEditException { + BlockState block = editSession.getBlock(position); + BlockState targetBlock = getTargetBlock(depth); + + if (block.equalsFuzzy(targetBlock)) { + return false; + } + + return editSession.setBlock(position, targetBlock); + } + @Override public boolean apply(BlockVector3 position, int depth) throws WorldEditException { if (mask.test(position)) { - affected++; - switch (depth) { - case 0: - editSession.setBlock(position, BlockTypes.GRASS_BLOCK.getDefaultState()); - break; - case 1: - case 2: - case 3: - editSession.setBlock(position, BlockTypes.DIRT.getDefaultState()); - break; - default: - editSession.setBlock(position, BlockTypes.STONE.getDefaultState()); + if (naturalize(position, depth)) { + ++affected; } } From fd1178a3d01ff9627c06853abcb862296ad39c57 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 10 Jun 2019 20:12:19 -0400 Subject: [PATCH 195/366] Fix item interact event. --- .../main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java index 672eed9fe..d875d4938 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java @@ -206,7 +206,7 @@ public class SpongeWorldEdit { } @Listener - public void onPlayerItemInteract(InteractItemEvent event, @Root Player spongePlayer) { + public void onPlayerItemInteract(InteractItemEvent.Secondary event, @Root Player spongePlayer) { if (platform == null) { return; } From efb7650d6f0109fcc2b4989691c8cb8224f7a5dc Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 11 Jun 2019 18:02:07 -0400 Subject: [PATCH 196/366] Fix some reload issues. And some unload issues. --- .../java/com/sk89q/worldedit/bukkit/BukkitWorld.java | 3 ++- .../com/sk89q/worldedit/bukkit/WorldEditPlugin.java | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) 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 38d82dc25..7b5af1a62 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 @@ -315,7 +315,8 @@ public class BukkitWorld extends AbstractWorld { } else if (other == null) { return false; } else if ((other instanceof BukkitWorld)) { - return ((BukkitWorld) other).getWorld().equals(getWorld()); + World otherWorld = ((BukkitWorld) other).worldRef.get(); + return otherWorld != null && otherWorld.equals(getWorld()); } else if (other instanceof com.sk89q.worldedit.world.World) { return ((com.sk89q.worldedit.world.World) other).getName().equals(getName()); } else { 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 18a7d69d2..4ac9a3ee1 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 @@ -136,10 +136,15 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // these don't stick around between reload loadAdapter(); loadConfig(); + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); } catch (Throwable ignored) { } } else { getServer().getPluginManager().registerEvents((worldInitListener = new WorldInitListener()), this); + loadAdapter(); // Need an adapter to work with special blocks with NBT data + setupRegistries(); + WorldEdit.getInstance().loadMappings(); + loadConfig(); // Load configuration } // Enable metrics @@ -148,12 +153,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { } private void setupWorldData() { - loadAdapter(); // Need an adapter to work with special blocks with NBT data - setupRegistries(); - WorldEdit.getInstance().loadMappings(); - loadConfig(); // Load configuration setupTags(); - WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); } From 6f7927bc5aa3936322de8d02cc49c9ffae0f417d Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 12 Jun 2019 21:51:22 -0400 Subject: [PATCH 197/366] Skip poi folders for snapshot restores. New to 1.14, Mojang stores .mca files which don't contain chunks in the poi folder. Note: we explicitly filter *out* the poi folder, instead of filtering *to* the regions folder, since old versions of minecraft had regions directly in the world folder (instead of a regions subfolder). --- .../main/java/com/sk89q/worldedit/EditSession.java | 12 +++++++----- .../worldedit/command/SnapshotUtilCommands.java | 4 +++- .../world/storage/TrueZipMcRegionChunkStore.java | 1 + .../world/storage/ZippedMcRegionChunkStore.java | 1 + 4 files changed, 12 insertions(+), 6 deletions(-) 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 43843e8a3..a0b0a1150 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -1307,14 +1307,16 @@ public class EditSession implements Extent, AutoCloseable { checkNotNull(origin); checkArgument(radius >= 0, "radius >= 0 required"); + Mask waterloggedMask = null; + if (waterlogged) { + Map stateMap = new HashMap<>(); + stateMap.put("waterlogged", "true"); + waterloggedMask = new BlockStateMask(this, stateMap, true); + } MaskIntersection mask = new MaskIntersection( new BoundedHeightMask(0, getWorld().getMaxY()), new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))), - waterlogged ? new MaskUnion( - getWorld().createLiquidMask(), - new BlockStateMask(this, new HashMap() {{ - put("waterlogged", "true"); - }}, true)) + waterlogged ? new MaskUnion(getWorld().createLiquidMask(), waterloggedMask) : getWorld().createLiquidMask()); BlockReplace replace; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java index 14a90e2fe..0b9ba7cfe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java @@ -133,7 +133,9 @@ public class SnapshotUtilCommands { if (restore.hadTotalFailure()) { String error = restore.getLastErrorMessage(); - if (error != null) { + if (!restore.getMissingChunks().isEmpty()) { + player.printError("Chunks were not present in snapshot."); + } else if (error != null) { player.printError("Errors prevented any blocks from being restored."); player.printError("Last error: " + error); } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java index 80e2f814d..a653844a9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/TrueZipMcRegionChunkStore.java @@ -101,6 +101,7 @@ public class TrueZipMcRegionChunkStore extends McRegionChunkStore { // Check for file if (pattern.matcher(testEntry.getName()).matches()) { folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf('/')); + if (folder.endsWith("poi")) continue; name = folder + "/" + name; break; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java index afb9cff72..f83ad89da 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/ZippedMcRegionChunkStore.java @@ -87,6 +87,7 @@ public class ZippedMcRegionChunkStore extends McRegionChunkStore { if (testEntry.getName().startsWith(worldName + "/")) { if (pattern.matcher(testEntry.getName()).matches()) { // does entry end in .mca folder = testEntry.getName().substring(0, testEntry.getName().lastIndexOf('/')); + if (folder.endsWith("poi")) continue; name = folder + "/" + name; break; } From 213cadf093273ef1477df43597283c837c7d1fad Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 13 Jun 2019 09:17:00 -0400 Subject: [PATCH 198/366] Import cleanup, ensure gradle uses https for deps, bump deps. --- worldedit-bukkit/build.gradle | 4 ++-- .../com/sk89q/worldedit/bukkit/BukkitCommandInspector.java | 3 --- .../java/com/sk89q/worldedit/bukkit/WorldEditListener.java | 5 +---- .../java/com/sk89q/worldedit/command/ChunkCommands.java | 1 - .../java/com/sk89q/worldedit/command/GeneralCommands.java | 1 - .../worldedit/command/argument/DirectionConverter.java | 1 - .../worldedit/extent/clipboard/io/NBTSchematicReader.java | 1 - .../io/legacycompat/EntityNBTCompatibilityHandler.java | 4 ---- .../io/legacycompat/Pre13HangingCompatibilityHandler.java | 1 - .../com/sk89q/worldedit/function/mask/ExpressionMask.java | 1 - .../com/sk89q/worldedit/function/mask/ExpressionMask2D.java | 1 - .../extent/transform/BlockTransformExtentTest.java | 1 - .../src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java | 3 --- .../main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java | 5 ----- worldedit-sponge/build.gradle | 6 +++--- .../sk89q/worldedit/sponge/adapter/SpongeImplAdapter.java | 1 - 16 files changed, 6 insertions(+), 33 deletions(-) diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index 28dc522c6..ba7a34f31 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -23,7 +23,7 @@ dependencies { implementation 'io.papermc:paperlib:1.0.2' compileOnly 'com.sk89q:dummypermscompat:1.10' implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' - implementation 'org.bstats:bstats-bukkit:1.4' + implementation 'org.bstats:bstats-bukkit:1.5' testCompile 'org.mockito:mockito-core:1.9.0-rc1' } @@ -52,7 +52,7 @@ shadowJar { include(dependency('org.slf4j:slf4j-api')) include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) relocate ("org.bstats", "com.sk89q.worldedit.bukkit.bstats") { - include(dependency("org.bstats:bstats-bukkit:1.4")) + include(dependency("org.bstats:bstats-bukkit:1.5")) } relocate ("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") { include(dependency("io.papermc:paperlib:1.0.2")) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java index 005d79259..972f7f5e1 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java @@ -24,12 +24,9 @@ import com.sk89q.worldedit.extension.platform.Actor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.enginehub.piston.CommandManager; -import org.enginehub.piston.CommandParameters; -import org.enginehub.piston.NoInputCommandParameters; import org.enginehub.piston.inject.InjectedValueStore; import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.MapBackedValueStore; -import org.enginehub.piston.inject.MemoizingValueAccess; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java index 8f19dc3a0..f32ca1ac5 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditListener.java @@ -37,12 +37,9 @@ import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; import org.enginehub.piston.CommandManager; -import org.enginehub.piston.CommandParameters; -import org.enginehub.piston.NoInputCommandParameters; import org.enginehub.piston.inject.InjectedValueStore; import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.MapBackedValueStore; -import org.enginehub.piston.inject.MemoizingValueAccess; import java.util.Optional; @@ -73,7 +70,7 @@ public class WorldEditListener implements Listener { } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - public void onPlayerCommand(PlayerCommandSendEvent event) { + public void onPlayerCommandSend(PlayerCommandSendEvent event) { InjectedValueStore store = MapBackedValueStore.create(); store.injectValue(Key.of(Actor.class), context -> Optional.of(plugin.wrapCommandSender(event.getPlayer()))); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index 3c097b992..af1e4e95d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -38,7 +38,6 @@ import com.sk89q.worldedit.world.storage.LegacyChunkStore; import com.sk89q.worldedit.world.storage.McRegionChunkStore; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; -import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.ArgFlag; import java.io.FileOutputStream; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 92ab5611d..38d92a34e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -24,7 +24,6 @@ import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.command.util.AsyncCommandBuilder; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java index 22e0b2fbe..d83bc51c6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/DirectionConverter.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.command.argument; import com.sk89q.worldedit.UnknownDirectionException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Direction; import org.enginehub.piston.CommandManager; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java index 12f1f1b41..cc8f9ee81 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/NBTSchematicReader.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.extent.clipboard.io; -import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; import java.io.IOException; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java index ffba0b566..389a596cb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/EntityNBTCompatibilityHandler.java @@ -20,12 +20,8 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.entity.EntityType; -import java.util.Map; - public interface EntityNBTCompatibilityHandler { boolean isAffectedEntity(EntityType type, CompoundTag entityTag); CompoundTag updateNBT(EntityType type, CompoundTag entityTag); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java index 62f40d79c..c42fab428 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.extent.clipboard.io.legacycompat; -import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTagBuilder; import com.sk89q.worldedit.internal.helper.MCDirections; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java index d8ddcc704..eba02d0a7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java index 0f4d9b198..a50c5e375 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.function.mask; import static com.google.common.base.Preconditions.checkNotNull; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java index c90f312fe..633e359f8 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java @@ -25,7 +25,6 @@ import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 4b6c8d6a5..14061d6e6 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -53,7 +53,6 @@ import net.minecraft.entity.EntityType; import net.minecraft.entity.item.EntityItem; import net.minecraft.init.Blocks; import net.minecraft.inventory.IInventory; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; import net.minecraft.nbt.NBTTagCompound; @@ -64,7 +63,6 @@ import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; @@ -88,7 +86,6 @@ import net.minecraft.world.gen.feature.SwampTreeFeature; import net.minecraft.world.gen.feature.TallTaigaTreeFeature; import net.minecraft.world.gen.feature.TreeFeature; import net.minecraft.world.storage.WorldInfo; -import net.minecraftforge.common.DimensionManager; import java.io.File; import java.lang.ref.WeakReference; diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index 897cebe16..e5628b03b 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -41,7 +41,6 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.item.ItemCategory; import com.sk89q.worldedit.world.item.ItemType; -import net.minecraft.client.Minecraft; import net.minecraft.command.CommandSource; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.tags.BlockTags; @@ -49,7 +48,6 @@ import net.minecraft.tags.ItemTags; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; -import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.CommandEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; @@ -62,12 +60,9 @@ import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; -import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.loading.FMLPaths; import net.minecraftforge.registries.ForgeRegistries; import org.apache.logging.log4j.LogManager; diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle index 6d75c4d84..a745869b6 100644 --- a/worldedit-sponge/build.gradle +++ b/worldedit-sponge/build.gradle @@ -1,7 +1,7 @@ buildscript { repositories { mavenCentral() - maven { url = "http://files.minecraftforge.net/maven" } + maven { url = "https://files.minecraftforge.net/maven" } maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } jcenter() } @@ -19,7 +19,7 @@ dependencies { compile project(':worldedit-core') compile project(':worldedit-libs:sponge') compile 'org.spongepowered:spongeapi:7.1.0' - compile 'org.bstats:bstats-sponge:1.4' + compile 'org.bstats:bstats-sponge:1.5' testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1' } @@ -42,7 +42,7 @@ jar { shadowJar { dependencies { relocate ("org.bstats", "com.sk89q.worldedit.sponge.bstats") { - include(dependency('org.bstats:bstats-sponge:1.4')) + include(dependency('org.bstats:bstats-sponge:1.5')) } } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/SpongeImplAdapter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/SpongeImplAdapter.java index d2ddf99e5..c6d5f11b6 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/SpongeImplAdapter.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/adapter/SpongeImplAdapter.java @@ -29,7 +29,6 @@ import com.sk89q.worldedit.util.Location; import org.spongepowered.api.entity.Entity; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.world.World; -import org.spongepowered.api.world.biome.BiomeType; /** * An interface for various things that can't be done through the Sponge API. From 7787f2c15e5243c963873a9975e944d5b97882e9 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 13 Jun 2019 10:17:37 -0400 Subject: [PATCH 199/366] Use AsyncCommandBuilder for /calc. --- .../worldedit/command/UtilityCommands.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 4388b129e..76e5d441e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.command.util.CreatureButcher; import com.sk89q.worldedit.command.util.EntityRemover; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.PrintCommandHelp; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; @@ -494,20 +495,20 @@ public class UtilityCommands { public void calc(Actor actor, @Arg(desc = "Expression to evaluate", variable = true) List input) { + Expression expression; try { - Expression expression = Expression.compile(String.join(" ", input)); - double result = expression.evaluate( - new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout()); - String formatted = formatter.format(result); - actor.print(SubtleFormat.wrap(input + " = ") - .append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE))); - } catch (EvaluationException e) { - actor.printError(String.format( - "'%s' could not be evaluated (error: %s)", input, e.getMessage())); + expression = Expression.compile(String.join(" ", input)); } catch (ExpressionException e) { actor.printError(String.format( "'%s' could not be parsed as a valid expression", input)); + return; } + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> { + double result = expression.evaluate( + new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout()); + String formatted = Double.isNaN(result) ? "NaN" : formatter.format(result); + return SubtleFormat.wrap(input + " = ").append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE)); + }, null); } @Command( From 6e833a9fe49eb88ef41d035891e6805baa33d4c8 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 13 Jun 2019 14:35:00 -0400 Subject: [PATCH 200/366] Correctly unwrap old CommandExceptions in AsyncCommandBuilder. --- .../com/sk89q/worldedit/command/util/AsyncCommandBuilder.java | 4 ++++ .../worldedit/util/formatting/component/PaginationBox.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java index d2f70a006..b01b2f4fd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/AsyncCommandBuilder.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.command.util; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.sk89q.worldedit.extension.platform.Actor; @@ -142,6 +143,9 @@ public final class AsyncCommandBuilder { try { if (exceptionConverter != null) { try { + if (orig instanceof com.sk89q.minecraft.util.commands.CommandException) { + throw new CommandExecutionException(orig, ImmutableList.of()); + } exceptionConverter.convert(orig); throw orig; } catch (CommandException converted) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java index 9308d326c..3f9b95267 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/PaginationBox.java @@ -79,7 +79,7 @@ public abstract class PaginationBox extends MessageBox { public Component create(int page) throws InvalidComponentException { if (page == 1 && getComponentsSize() == 0) { - return getContents().reset().append("There's nothing to see here").create(); + return getContents().reset().append("No results found.").create(); } int pageCount = (int) Math.ceil(getComponentsSize() / (double) componentsPerPage); if (page < 1 || page > pageCount) { From e1c191599ca6a60550e5f60ff195cb7c1574d70c Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 13 Jun 2019 14:22:15 -0400 Subject: [PATCH 201/366] Implement item brushes and item NBT for bukkit. This allows usage of `/br item` and the `offhand` syntax for item parser to use NBT. --- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 6 ++++ .../sk89q/worldedit/bukkit/BukkitWorld.java | 12 +++++++ .../bukkit/adapter/BukkitImplAdapter.java | 34 ++++++++++++++++++ .../src/main/resources/worldedit-adapters.jar | Bin 642635 -> 654661 bytes 4 files changed, 52 insertions(+) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index b8418d03d..f311a9e1b 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -439,6 +439,9 @@ public class BukkitAdapter { */ public static BaseItemStack adapt(ItemStack itemStack) { checkNotNull(itemStack); + if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) { + return WorldEditPlugin.getInstance().getBukkitImplAdapter().adapt(itemStack); + } return new BaseItemStack(ItemTypes.get(itemStack.getType().getKey().toString()), itemStack.getAmount()); } @@ -450,6 +453,9 @@ public class BukkitAdapter { */ public static ItemStack adapt(BaseItemStack item) { checkNotNull(item); + if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) { + return WorldEditPlugin.getInstance().getBukkitImplAdapter().adapt(item); + } return new ItemStack(adapt(item.getType()), item.getAmount()); } } 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 7b5af1a62..cd12e220c 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 @@ -22,6 +22,7 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.entity.BaseEntity; @@ -30,6 +31,7 @@ import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.biome.BiomeType; @@ -461,6 +463,16 @@ public class BukkitWorld extends AbstractWorld { return false; } + @Override + public boolean useItem(BlockVector3 position, BaseItem item, Direction face) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + return adapter.simulateItemUse(getWorld(), position, item, face); + } + + return false; + } + @Override public BiomeType getBiome(BlockVector2 position) { return BukkitAdapter.adapt(getWorld().getBiome(position.getBlockX(), position.getBlockZ())); 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 fce88bd29..984c5ad2a 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 @@ -20,17 +20,22 @@ package com.sk89q.worldedit.bukkit.adapter; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import java.util.Map; @@ -126,4 +131,33 @@ public interface BukkitImplAdapter { * @param player The player */ void sendFakeOP(Player player); + + /** + * Simulates a player using an item. + * + * @param world the world + * @param position the location + * @param item the item to be used + * @param face the direction in which to "face" when using the item + * @return whether the usage was successful + */ + default boolean simulateItemUse(World world, BlockVector3 position, BaseItem item, Direction face) { + return false; + } + + /** + * Create a Bukkit ItemStack with NBT, if available. + * + * @param item the WorldEdit BaseItemStack to adapt + * @return the Bukkit ItemStack + */ + ItemStack adapt(BaseItemStack item); + + /** + * Create a WorldEdit ItemStack with NBT, if available. + * + * @param itemStack the Bukkit ItemStack to adapt + * @return the WorldEdit BaseItemStack + */ + BaseItemStack adapt(ItemStack itemStack); } diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index 0045effc1a6f4beceef09da3c5406e99ea23f526..bd93b4a5d2221d4409b7e977948e727754baef09 100644 GIT binary patch delta 152987 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

    Pz!oo%Y=*FTo)-V}9P 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 delta 141113 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 Date: Fri, 14 Jun 2019 18:09:21 -0400 Subject: [PATCH 202/366] Bring FakePlayer cache to Forge. --- .../com/sk89q/worldedit/forge/ForgeWorld.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 14061d6e6..8361f9836 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -21,6 +21,9 @@ package com.sk89q.worldedit.forge; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.io.Files; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; @@ -92,6 +95,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Random; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ThreadLocalRandom; import javax.annotation.Nullable; @@ -241,11 +245,19 @@ public class ForgeWorld extends AbstractWorld { return false; } + private static LoadingCache fakePlayers + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(WorldEditFakePlayer::new)); + @Override public boolean useItem(BlockVector3 position, BaseItem item, Direction face) { ItemStack stack = ForgeAdapter.adapt(new BaseItemStack(item.getType(), item.getNbtData(), 1)); - World world = getWorld(); - final WorldEditFakePlayer fakePlayer = new WorldEditFakePlayer((WorldServer) world); + WorldServer world = (WorldServer) getWorld(); + final WorldEditFakePlayer fakePlayer; + try { + fakePlayer = fakePlayers.get(world); + } catch (ExecutionException ignored) { + return false; + } fakePlayer.setHeldItem(EnumHand.MAIN_HAND, stack); fakePlayer.setLocationAndAngles(position.getBlockX(), position.getBlockY(), position.getBlockZ(), (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); From a3a175ab8cb76e336e40d29e63c633bf64b21226 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 20 Feb 2019 23:47:33 -0800 Subject: [PATCH 203/366] Initial attempt at binding state IDs --- .../worldedit/bukkit/BukkitBlockRegistry.java | 10 ++++++++ .../bukkit/adapter/BukkitImplAdapter.java | 12 ++++++++++ .../internal/block/BlockStateIdAcess.java | 24 +++++++++++++++++++ .../worldedit/world/block/BlockState.java | 19 +++++++++++++-- .../world/registry/BlockRegistry.java | 10 ++++++++ .../world/registry/BundledBlockRegistry.java | 7 ++++++ .../world/registry/BundledItemData.java | 2 +- .../sk89q/worldedit/forge/ForgeAdapter.java | 4 ++-- .../worldedit/forge/ForgeBlockRegistry.java | 9 +++++++ .../com/sk89q/worldedit/forge/ForgeWorld.java | 7 +++++- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 3 +++ 11 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAcess.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java index 3400fd59f..43c3f330d 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.registry.BundledBlockRegistry; import com.sk89q.worldedit.world.registry.PassthroughBlockMaterial; @@ -28,6 +29,7 @@ import org.bukkit.Material; import java.util.EnumMap; import java.util.Map; +import java.util.OptionalInt; import javax.annotation.Nullable; @@ -54,6 +56,14 @@ public class BukkitBlockRegistry extends BundledBlockRegistry { return super.getProperties(blockType); } + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) { + return WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state); + } + return super.getInternalBlockStateId(state); + } + public static class BukkitBlockMaterial extends PassthroughBlockMaterial { private final Material material; 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 984c5ad2a..f21d0917a 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 @@ -38,6 +38,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import java.util.Map; +import java.util.OptionalInt; import javax.annotation.Nullable; @@ -160,4 +161,15 @@ public interface BukkitImplAdapter { * @return the WorldEdit BaseItemStack */ BaseItemStack adapt(ItemStack itemStack); + + + /** + * Retrieve the internal ID for a given state, if possible. + * + * @param state The block state + * @return the internal ID of the state + */ + default OptionalInt getInternalBlockStateId(BlockState state) { + return OptionalInt.empty(); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAcess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAcess.java new file mode 100644 index 000000000..766537776 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAcess.java @@ -0,0 +1,24 @@ +package com.sk89q.worldedit.internal.block; + +import com.sk89q.worldedit.world.block.BlockState; + +import java.util.OptionalInt; + +public class BlockStateIdAcess { + + public interface Provider { + + OptionalInt getBlockStateId(BlockState holder); + } + + private static Provider blockStateStateId; + + public static void setBlockStateStateId(Provider blockStateStateId) { + BlockStateIdAcess.blockStateStateId = blockStateStateId; + } + + public static OptionalInt getBlockStateId(BlockState holder) { + return blockStateStateId.getBlockStateId((BlockState) holder); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 5b276badb..7fed9efde 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -26,7 +26,10 @@ import com.google.common.collect.Maps; import com.google.common.collect.Table; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.internal.block.BlockStateIdAcess; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.registry.BlockRegistry; import java.util.Collections; import java.util.Comparator; @@ -35,6 +38,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.OptionalInt; import java.util.Set; /** @@ -42,9 +46,14 @@ import java.util.Set; */ @SuppressWarnings("unchecked") public class BlockState implements BlockStateHolder { + + static { + BlockStateIdAcess.setBlockStateStateId(x -> x.internalId); + } private final BlockType blockType; private final Map, Object> values; + private OptionalInt internalId = OptionalInt.empty(); private BaseBlock emptyBaseBlock; @@ -56,8 +65,14 @@ public class BlockState implements BlockStateHolder { this.values = new LinkedHashMap<>(); this.emptyBaseBlock = new BaseBlock(this); } + + BlockState initializeId(BlockRegistry registry) { + this.internalId = registry.getInternalBlockStateId(this); + return this; + } static Map, Object>, BlockState> generateStateMap(BlockType blockType) { + BlockRegistry registry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getRegistries().getBlockRegistry(); Map, Object>, BlockState> stateMap = new LinkedHashMap<>(); List> properties = blockType.getProperties(); @@ -71,7 +86,7 @@ public class BlockState implements BlockStateHolder { List> valueLists = Lists.cartesianProduct(separatedValues); for (List valueList : valueLists) { Map, Object> valueMap = Maps.newTreeMap(Comparator.comparing(Property::getName)); - BlockState stateMaker = new BlockState(blockType); + BlockState stateMaker = new BlockState(blockType).initializeId(registry); for (int i = 0; i < valueList.size(); i++) { Property property = properties.get(i); Object value = valueList.get(i); @@ -84,7 +99,7 @@ public class BlockState implements BlockStateHolder { if (stateMap.isEmpty()) { // No properties. - stateMap.put(new LinkedHashMap<>(), new BlockState(blockType)); + stateMap.put(new LinkedHashMap<>(), new BlockState(blockType).initializeId(registry)); } for (BlockState state : stateMap.values()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java index e33998a12..fb572f019 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java @@ -20,9 +20,11 @@ package com.sk89q.worldedit.world.registry; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import java.util.Map; +import java.util.OptionalInt; import javax.annotation.Nullable; @@ -57,4 +59,12 @@ public interface BlockRegistry { */ Map> getProperties(BlockType blockType); + /** + * Retrieve the internal ID for a given state, if possible. + * + * @param state The block state + * @return the internal ID of the state + */ + OptionalInt getInternalBlockStateId(BlockState state); + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java index 62c8b5c3a..0e5615475 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java @@ -20,10 +20,12 @@ package com.sk89q.worldedit.world.registry; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import java.util.Collections; import java.util.Map; +import java.util.OptionalInt; import javax.annotation.Nullable; @@ -52,4 +54,9 @@ public class BundledBlockRegistry implements BlockRegistry { return Collections.emptyMap(); // Oof } + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + return OptionalInt.empty(); + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java index 4e1af0422..86bd253a7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java @@ -75,7 +75,7 @@ public class BundledItemData { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); Gson gson = gsonBuilder.create(); - URL url = ResourceLoader.getResource(BundledItemData.class,"items.json"); + URL url = ResourceLoader.getResource(BundledItemData.class,"items.json");F if (url == null) { throw new IOException("Could not find items.json"); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java index bc6448636..3618093c8 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.forge; +import static com.google.common.base.Preconditions.checkNotNull; + import com.google.common.collect.ImmutableList; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; @@ -61,8 +63,6 @@ import java.util.Map; import java.util.TreeMap; import java.util.stream.Collectors; -import static com.google.common.base.Preconditions.checkNotNull; - public final class ForgeAdapter { private ForgeAdapter() { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java index e918d3e52..a44b19e3c 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java @@ -20,17 +20,20 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BundledBlockRegistry; import net.minecraft.block.Block; import net.minecraft.block.material.Material; +import net.minecraft.block.state.IBlockState; import net.minecraft.state.IProperty; import net.minecraftforge.fml.loading.FMLLoader; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.OptionalInt; import java.util.TreeMap; import javax.annotation.Nullable; @@ -73,4 +76,10 @@ public class ForgeBlockRegistry extends BundledBlockRegistry { return map; } + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + IBlockState equivalent = ForgeAdapter.adaptState(state); + return OptionalInt.of(Block.getStateId(equivalent)); + } + } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 8361f9836..fe3abdee7 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.block.BlockStateIdAcess; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -50,6 +51,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherTypes; +import net.minecraft.block.Block; import net.minecraft.block.BlockLeaves; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.EntityType; @@ -94,6 +96,8 @@ import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.OptionalInt; import java.util.Random; import java.util.concurrent.ExecutionException; import java.util.concurrent.ThreadLocalRandom; @@ -173,7 +177,8 @@ public class ForgeWorld extends AbstractWorld { Chunk chunk = world.getChunk(x >> 4, z >> 4); BlockPos pos = new BlockPos(x, y, z); IBlockState old = chunk.getBlockState(pos); - IBlockState newState = ForgeAdapter.adapt(block.toImmutableState()); + OptionalInt stateId = BlockStateIdAcess.getBlockStateId(block.toImmutableState()); + IBlockState newState = stateId.isPresent() ? Block.getStateById(stateId.getAsInt()) : ForgeAdapter.adaptState(block.toImmutableState()); IBlockState successState = chunk.setBlockState(pos, newState, false); boolean successful = successState != null; diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index e5628b03b..d681bafea 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -175,6 +175,9 @@ public class ForgeWorldEdit { ItemCategory.REGISTRY.register(name.toString(), new ItemCategory(name.toString())); } } + + config = new ForgeConfiguration(this); + config.load(); } @SubscribeEvent From 2571efb5c3df99236f06bf892deb0a9a65dec7f5 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 29 Apr 2019 19:59:41 +1000 Subject: [PATCH 204/366] Few fixes for worldedit changes --- .../internal/block/BlockStateIdAccess.java | 46 +++++++++++++++++++ .../internal/block/BlockStateIdAcess.java | 24 ---------- .../worldedit/world/block/BlockState.java | 4 +- .../world/registry/BundledItemData.java | 2 +- .../worldedit/forge/ForgeBlockRegistry.java | 2 +- .../com/sk89q/worldedit/forge/ForgeWorld.java | 7 ++- 6 files changed, 53 insertions(+), 32 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAcess.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java new file mode 100644 index 000000000..f7f9d66f0 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java @@ -0,0 +1,46 @@ +/* + * 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.internal.block; + +import com.sk89q.worldedit.world.block.BlockState; + +import java.util.OptionalInt; + +public class BlockStateIdAccess { + + private BlockStateIdAccess() { + } + + public interface Provider { + + OptionalInt getBlockStateId(BlockState holder); + } + + private static Provider blockStateStateId; + + public static void setBlockStateStateId(Provider blockStateStateId) { + BlockStateIdAccess.blockStateStateId = blockStateStateId; + } + + public static OptionalInt getBlockStateId(BlockState holder) { + return blockStateStateId.getBlockStateId((BlockState) holder); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAcess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAcess.java deleted file mode 100644 index 766537776..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAcess.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.sk89q.worldedit.internal.block; - -import com.sk89q.worldedit.world.block.BlockState; - -import java.util.OptionalInt; - -public class BlockStateIdAcess { - - public interface Provider { - - OptionalInt getBlockStateId(BlockState holder); - } - - private static Provider blockStateStateId; - - public static void setBlockStateStateId(Provider blockStateStateId) { - BlockStateIdAcess.blockStateStateId = blockStateStateId; - } - - public static OptionalInt getBlockStateId(BlockState holder) { - return blockStateStateId.getBlockStateId((BlockState) holder); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 7fed9efde..7463fefb1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -27,7 +27,7 @@ import com.google.common.collect.Table; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.internal.block.BlockStateIdAcess; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.registry.BlockRegistry; @@ -48,7 +48,7 @@ import java.util.Set; public class BlockState implements BlockStateHolder { static { - BlockStateIdAcess.setBlockStateStateId(x -> x.internalId); + BlockStateIdAccess.setBlockStateStateId(x -> x.internalId); } private final BlockType blockType; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java index 86bd253a7..4e1af0422 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java @@ -75,7 +75,7 @@ public class BundledItemData { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); Gson gson = gsonBuilder.create(); - URL url = ResourceLoader.getResource(BundledItemData.class,"items.json");F + URL url = ResourceLoader.getResource(BundledItemData.class,"items.json"); if (url == null) { throw new IOException("Could not find items.json"); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java index a44b19e3c..042d9e230 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java @@ -78,7 +78,7 @@ public class ForgeBlockRegistry extends BundledBlockRegistry { @Override public OptionalInt getInternalBlockStateId(BlockState state) { - IBlockState equivalent = ForgeAdapter.adaptState(state); + IBlockState equivalent = ForgeAdapter.adapt(state); return OptionalInt.of(Block.getStateId(equivalent)); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index fe3abdee7..3b1dabeb2 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -34,7 +34,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.internal.Constants; -import com.sk89q.worldedit.internal.block.BlockStateIdAcess; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; @@ -96,7 +96,6 @@ import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.OptionalInt; import java.util.Random; import java.util.concurrent.ExecutionException; @@ -177,8 +176,8 @@ public class ForgeWorld extends AbstractWorld { Chunk chunk = world.getChunk(x >> 4, z >> 4); BlockPos pos = new BlockPos(x, y, z); IBlockState old = chunk.getBlockState(pos); - OptionalInt stateId = BlockStateIdAcess.getBlockStateId(block.toImmutableState()); - IBlockState newState = stateId.isPresent() ? Block.getStateById(stateId.getAsInt()) : ForgeAdapter.adaptState(block.toImmutableState()); + OptionalInt stateId = BlockStateIdAccess.getBlockStateId(block.toImmutableState()); + IBlockState newState = stateId.isPresent() ? Block.getStateById(stateId.getAsInt()) : ForgeAdapter.adapt(block.toImmutableState()); IBlockState successState = chunk.setBlockState(pos, newState, false); boolean successful = successState != null; From dc21b4df58111d3d276ffb2851441757d2335627 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 12 May 2019 14:19:46 -0400 Subject: [PATCH 205/366] This does something idk. --- .../worldedit/bukkit/BukkitBlockRegistry.java | 31 ++++++++++++++++--- .../sk89q/worldedit/bukkit/BukkitWorld.java | 14 +++++++-- .../sk89q/worldedit/regions/CuboidRegion.java | 6 ++-- .../worldedit/world/block/BlockState.java | 5 +-- .../world/registry/BlockRegistry.java | 7 +++++ .../world/registry/BundledBlockRegistry.java | 5 +++ 6 files changed, 57 insertions(+), 11 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java index 43c3f330d..79690df26 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.bukkit; +import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.block.BlockState; @@ -34,8 +35,8 @@ import java.util.OptionalInt; import javax.annotation.Nullable; public class BukkitBlockRegistry extends BundledBlockRegistry { - private Map materialMap = new EnumMap<>(Material.class); + private BlockState[] statesById = new BlockState[2 << 14]; @Nullable @Override @@ -58,10 +59,32 @@ public class BukkitBlockRegistry extends BundledBlockRegistry { @Override public OptionalInt getInternalBlockStateId(BlockState state) { - if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) { - return WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state); + if (state.getBlockType() == BlockTypes.AIR) { + statesById[0] = state; + return OptionalInt.of(0); } - return super.getInternalBlockStateId(state); + final OptionalInt id; + if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) { + id = WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state); + } else { + id = super.getInternalBlockStateId(state); + } + if (id.isPresent()) { + final int idx = id.getAsInt(); + if (statesById.length <= idx) { + BlockState[] newArr = new BlockState[statesById.length * 2]; + System.arraycopy(statesById, 0, newArr, 0, statesById.length); + statesById = newArr; + } + statesById[idx] = state; + } + return id; + } + + @Nullable + @Override + public BlockState getBlockStateByInternalId(int id) { + return id >= statesById.length ? null : statesById[id]; } public static class BukkitBlockMaterial extends PassthroughBlockMaterial { 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 cd12e220c..c8d8f6259 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 @@ -415,8 +415,18 @@ public class BukkitWorld extends AbstractWorld { @Override public com.sk89q.worldedit.world.block.BlockState getBlock(BlockVector3 position) { - Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - return BukkitAdapter.adapt(bukkitBlock.getBlockData()); + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + try { + return adapter.getBlock(BukkitAdapter.adapt(getWorld(), position)).toImmutableState(); + } catch (Exception e) { + Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + return BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } + } else { + Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + return BukkitAdapter.adapt(bukkitBlock.getBlockData()); + } } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java index e011228d0..3cfddc15d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/CuboidRegion.java @@ -345,9 +345,9 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion { BlockVector3 answer = BlockVector3.at(nextX, nextY, nextZ); if (++nextX > max.getBlockX()) { nextX = min.getBlockX(); - if (++nextY > max.getBlockY()) { - nextY = min.getBlockY(); - if (++nextZ > max.getBlockZ()) { + if (++nextZ > max.getBlockZ()) { + nextZ = min.getBlockZ(); + if (++nextY > max.getBlockY()) { nextX = Integer.MIN_VALUE; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 7463fefb1..98c5966c7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -46,7 +46,7 @@ import java.util.Set; */ @SuppressWarnings("unchecked") public class BlockState implements BlockStateHolder { - + static { BlockStateIdAccess.setBlockStateStateId(x -> x.internalId); } @@ -86,13 +86,14 @@ public class BlockState implements BlockStateHolder { List> valueLists = Lists.cartesianProduct(separatedValues); for (List valueList : valueLists) { Map, Object> valueMap = Maps.newTreeMap(Comparator.comparing(Property::getName)); - BlockState stateMaker = new BlockState(blockType).initializeId(registry); + BlockState stateMaker = new BlockState(blockType); for (int i = 0; i < valueList.size(); i++) { Property property = properties.get(i); Object value = valueList.get(i); valueMap.put(property, value); stateMaker.setState(property, value); } + stateMaker.initializeId(registry); stateMap.put(valueMap, stateMaker); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java index fb572f019..58a15ff30 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java @@ -67,4 +67,11 @@ public interface BlockRegistry { */ OptionalInt getInternalBlockStateId(BlockState state); + /** + * Retrieve a block state by its internal ID, if possible. + * + * @param id The internal ID + * @return the block state, if available + */ + BlockState getBlockStateByInternalId(int id); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java index 0e5615475..0b52ae01a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java @@ -59,4 +59,9 @@ public class BundledBlockRegistry implements BlockRegistry { return OptionalInt.empty(); } + @Override + public BlockState getBlockStateByInternalId(int id) { + return null; + } + } From 8c17aab9c5c75ada5b35aeaa974a18c1551fc211 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 23 May 2019 22:19:25 -0700 Subject: [PATCH 206/366] Clean-up some misc. parts of the code --- .../com/sk89q/worldedit/bukkit/BukkitWorld.java | 13 ++++++++----- .../com/sk89q/worldedit/world/block/BlockState.java | 2 +- .../worldedit/world/registry/BlockRegistry.java | 1 + .../com/sk89q/worldedit/forge/ForgeAdapter.java | 4 ++-- .../sk89q/worldedit/forge/ForgeBlockRegistry.java | 13 +++++++++++++ .../com/sk89q/worldedit/forge/ForgeWorldEdit.java | 5 +---- 6 files changed, 26 insertions(+), 12 deletions(-) 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 c8d8f6259..d17999fc7 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 @@ -413,6 +413,8 @@ public class BukkitWorld extends AbstractWorld { getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).breakNaturally(); } + private static volatile boolean hasWarnedImplError = false; + @Override public com.sk89q.worldedit.world.block.BlockState getBlock(BlockVector3 position) { BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); @@ -420,13 +422,14 @@ public class BukkitWorld extends AbstractWorld { try { return adapter.getBlock(BukkitAdapter.adapt(getWorld(), position)).toImmutableState(); } catch (Exception e) { - Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - return BukkitAdapter.adapt(bukkitBlock.getBlockData()); + if (!hasWarnedImplError) { + hasWarnedImplError = true; + logger.warn("Unable to retrieve block via impl adapter", e); + } } - } else { - Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - return BukkitAdapter.adapt(bukkitBlock.getBlockData()); } + Block bukkitBlock = getWorld().getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + return BukkitAdapter.adapt(bukkitBlock.getBlockData()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 98c5966c7..1cd83cb3e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -65,7 +65,7 @@ public class BlockState implements BlockStateHolder { this.values = new LinkedHashMap<>(); this.emptyBaseBlock = new BaseBlock(this); } - + BlockState initializeId(BlockRegistry registry) { this.internalId = registry.getInternalBlockStateId(this); return this; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java index 58a15ff30..d17662b0e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java @@ -73,5 +73,6 @@ public interface BlockRegistry { * @param id The internal ID * @return the block state, if available */ + @Nullable BlockState getBlockStateByInternalId(int id); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java index 3618093c8..bc6448636 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.forge; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.collect.ImmutableList; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; @@ -63,6 +61,8 @@ import java.util.Map; import java.util.TreeMap; import java.util.stream.Collectors; +import static com.google.common.base.Preconditions.checkNotNull; + public final class ForgeAdapter { private ForgeAdapter() { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java index 042d9e230..998f8674e 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java @@ -27,8 +27,11 @@ import com.sk89q.worldedit.world.registry.BundledBlockRegistry; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; import net.minecraft.state.IProperty; +import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.fml.loading.FMLLoader; +import net.minecraftforge.registries.GameData; import java.util.Collection; import java.util.HashMap; @@ -40,6 +43,7 @@ import javax.annotation.Nullable; public class ForgeBlockRegistry extends BundledBlockRegistry { + private final int airId = Block.getStateId(Blocks.AIR.getDefaultState()); private Map materialMap = new HashMap<>(); @Nullable @@ -82,4 +86,13 @@ public class ForgeBlockRegistry extends BundledBlockRegistry { return OptionalInt.of(Block.getStateId(equivalent)); } + @Override + public BlockState getBlockStateByInternalId(int id) { + IBlockState equivalent = Block.getStateById(id); + if (equivalent.equals(Blocks.AIR.getDefaultState()) && id != airId) { + // We didn't find a match. + return null; + } + return ForgeAdapter.adapt(equivalent); + } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index d681bafea..a72a881a6 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -175,9 +175,6 @@ public class ForgeWorldEdit { ItemCategory.REGISTRY.register(name.toString(), new ItemCategory(name.toString())); } } - - config = new ForgeConfiguration(this); - config.load(); } @SubscribeEvent @@ -211,7 +208,7 @@ public class ForgeWorldEdit { InternalPacketHandler.getHandler().sendToServer(new LeftClickAirEventMessage()); return; } - + boolean isLeftDeny = event instanceof PlayerInteractEvent.LeftClickBlock && ((PlayerInteractEvent.LeftClickBlock) event) .getUseItem() == Event.Result.DENY; From 27c7d488a255084d9a9d0004c6172f8b898bba8b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 23 May 2019 23:19:23 -0700 Subject: [PATCH 207/366] Add perf. improvments for Forge --- .../worldedit/bukkit/BukkitBlockRegistry.java | 6 ----- .../internal/block/BlockStateIdAccess.java | 27 ++++++++++++++++++- .../worldedit/world/block/BlockState.java | 1 + .../world/registry/BlockRegistry.java | 8 ------ .../world/registry/BundledBlockRegistry.java | 5 ---- .../worldedit/forge/ForgeBlockRegistry.java | 17 +----------- .../com/sk89q/worldedit/forge/ForgeWorld.java | 13 ++++++--- 7 files changed, 37 insertions(+), 40 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java index 79690df26..3100fde4e 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java @@ -81,12 +81,6 @@ public class BukkitBlockRegistry extends BundledBlockRegistry { return id; } - @Nullable - @Override - public BlockState getBlockStateByInternalId(int id) { - return id >= statesById.length ? null : statesById[id]; - } - public static class BukkitBlockMaterial extends PassthroughBlockMaterial { private final Material material; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java index f7f9d66f0..88ed3d93b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java @@ -21,8 +21,12 @@ package com.sk89q.worldedit.internal.block; import com.sk89q.worldedit.world.block.BlockState; +import javax.annotation.Nullable; +import java.util.Arrays; import java.util.OptionalInt; +import static com.google.common.base.Preconditions.checkState; + public class BlockStateIdAccess { private BlockStateIdAccess() { @@ -40,7 +44,28 @@ public class BlockStateIdAccess { } public static OptionalInt getBlockStateId(BlockState holder) { - return blockStateStateId.getBlockStateId((BlockState) holder); + return blockStateStateId.getBlockStateId(holder); + } + + public static @Nullable BlockState getBlockStateById(int id) { + return id < blockStates.length ? blockStates[id] : null; + } + + private static BlockState[] blockStates = new BlockState[2 << 14]; + + public static void register(BlockState blockState) { + OptionalInt id = getBlockStateId(blockState); + if (id.isPresent()) { + int i = id.getAsInt(); + while (i >= blockStates.length) { + blockStates = Arrays.copyOf(blockStates, blockStates.length + blockStates.length >> 1); + } + BlockState existing = blockStates[i]; + checkState(existing == null || existing == blockState, + "BlockState %s is using the same block ID (%s) as BlockState %s", + blockState, i, existing); + blockStates[i] = blockState; + } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 1cd83cb3e..aeeae8210 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -68,6 +68,7 @@ public class BlockState implements BlockStateHolder { BlockState initializeId(BlockRegistry registry) { this.internalId = registry.getInternalBlockStateId(this); + BlockStateIdAccess.register(this); return this; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java index d17662b0e..fb572f019 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java @@ -67,12 +67,4 @@ public interface BlockRegistry { */ OptionalInt getInternalBlockStateId(BlockState state); - /** - * Retrieve a block state by its internal ID, if possible. - * - * @param id The internal ID - * @return the block state, if available - */ - @Nullable - BlockState getBlockStateByInternalId(int id); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java index 0b52ae01a..0e5615475 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockRegistry.java @@ -59,9 +59,4 @@ public class BundledBlockRegistry implements BlockRegistry { return OptionalInt.empty(); } - @Override - public BlockState getBlockStateByInternalId(int id) { - return null; - } - } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java index 998f8674e..8751fff89 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java @@ -27,23 +27,18 @@ import com.sk89q.worldedit.world.registry.BundledBlockRegistry; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; -import net.minecraft.init.Blocks; import net.minecraft.state.IProperty; -import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.fml.loading.FMLLoader; -import net.minecraftforge.registries.GameData; +import javax.annotation.Nullable; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.OptionalInt; import java.util.TreeMap; -import javax.annotation.Nullable; - public class ForgeBlockRegistry extends BundledBlockRegistry { - private final int airId = Block.getStateId(Blocks.AIR.getDefaultState()); private Map materialMap = new HashMap<>(); @Nullable @@ -85,14 +80,4 @@ public class ForgeBlockRegistry extends BundledBlockRegistry { IBlockState equivalent = ForgeAdapter.adapt(state); return OptionalInt.of(Block.getStateId(equivalent)); } - - @Override - public BlockState getBlockStateByInternalId(int id) { - IBlockState equivalent = Block.getStateById(id); - if (equivalent.equals(Blocks.AIR.getDefaultState()) && id != airId) { - // We didn't find a match. - return null; - } - return ForgeAdapter.adapt(equivalent); - } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 3b1dabeb2..f0c00dd45 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.forge; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -92,6 +90,7 @@ import net.minecraft.world.gen.feature.TallTaigaTreeFeature; import net.minecraft.world.gen.feature.TreeFeature; import net.minecraft.world.storage.WorldInfo; +import javax.annotation.Nullable; import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -101,7 +100,7 @@ import java.util.Random; import java.util.concurrent.ExecutionException; import java.util.concurrent.ThreadLocalRandom; -import javax.annotation.Nullable; +import static com.google.common.base.Preconditions.checkNotNull; /** * An adapter to Minecraft worlds for WorldEdit. @@ -464,13 +463,19 @@ public class ForgeWorld extends AbstractWorld { position.getBlockZ() ); + BlockState matchingBlock = BlockStateIdAccess.getBlockStateById(Block.getStateId(mcState)); + if (matchingBlock != null) { + return matchingBlock; + } + return ForgeAdapter.adapt(mcState); } @Override public BaseBlock getFullBlock(BlockVector3 position) { BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - TileEntity tile = getWorld().getTileEntity(pos); + // Avoid creation by using the CHECK mode -- if it's needed, it'll be re-created anyways + TileEntity tile = getWorld().getChunk(pos).getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK); if (tile != null) { return getBlock(position).toBaseBlock(NBTConverter.fromNative(TileEntityUtils.copyNbtData(tile))); From 0088fe79b31f5de894354dbdcd5a861aaf44e98e Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 14 Jun 2019 20:34:38 -0400 Subject: [PATCH 208/366] Cleanup Bukkit internal id usage. --- .../worldedit/bukkit/BukkitBlockRegistry.java | 22 ++---------------- .../sk89q/worldedit/bukkit/BukkitWorld.java | 8 +++---- .../src/main/resources/worldedit-adapters.jar | Bin 654661 -> 657067 bytes .../internal/block/BlockStateIdAccess.java | 2 +- 4 files changed, 6 insertions(+), 26 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java index 3100fde4e..3acaee79a 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.bukkit; -import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.block.BlockState; @@ -36,7 +35,6 @@ import javax.annotation.Nullable; public class BukkitBlockRegistry extends BundledBlockRegistry { private Map materialMap = new EnumMap<>(Material.class); - private BlockState[] statesById = new BlockState[2 << 14]; @Nullable @Override @@ -59,26 +57,10 @@ public class BukkitBlockRegistry extends BundledBlockRegistry { @Override public OptionalInt getInternalBlockStateId(BlockState state) { - if (state.getBlockType() == BlockTypes.AIR) { - statesById[0] = state; - return OptionalInt.of(0); - } - final OptionalInt id; if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) { - id = WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state); - } else { - id = super.getInternalBlockStateId(state); + return WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state); } - if (id.isPresent()) { - final int idx = id.getAsInt(); - if (statesById.length <= idx) { - BlockState[] newArr = new BlockState[statesById.length * 2]; - System.arraycopy(statesById, 0, newArr, 0, statesById.length); - statesById = newArr; - } - statesById[idx] = state; - } - return id; + return OptionalInt.empty(); } public static class BukkitBlockMaterial extends PassthroughBlockMaterial { 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 d17999fc7..1613f46eb 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 @@ -48,6 +48,7 @@ import org.bukkit.block.Chest; import org.bukkit.entity.Entity; import org.bukkit.inventory.DoubleChestInventory; import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; import org.slf4j.Logger; import javax.annotation.Nullable; @@ -238,15 +239,12 @@ public class BukkitWorld extends AbstractWorld { @Override public boolean clearContainerBlockContents(BlockVector3 pt) { Block block = getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - if (block == null) { - return false; - } BlockState state = block.getState(); - if (!(state instanceof org.bukkit.inventory.InventoryHolder)) { + if (!(state instanceof InventoryHolder)) { return false; } - org.bukkit.inventory.InventoryHolder chest = (org.bukkit.inventory.InventoryHolder) state; + InventoryHolder chest = (InventoryHolder) state; Inventory inven = chest.getInventory(); if (chest instanceof Chest) { inven = getBlockInventory((Chest) chest); diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index bd93b4a5d2221d4409b7e977948e727754baef09..b940ae841de83467e67a4c60e56ac37cce3aef6c 100644 GIT binary patch delta 57870 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 delta 55578 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 XbribAK)0Cx?=6N95kmw3-hciVm2Q?Y diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java index 88ed3d93b..52af247c9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java @@ -27,7 +27,7 @@ import java.util.OptionalInt; import static com.google.common.base.Preconditions.checkState; -public class BlockStateIdAccess { +public final class BlockStateIdAccess { private BlockStateIdAccess() { } From 0aa0dbfd11903894e8757f6b654d9e315b46bc98 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 15 Jun 2019 12:09:48 -0400 Subject: [PATCH 209/366] Fix BlockTransformExtent rotating directional boolean properties. Also add support for redstone dust, which is directional non-boolean. (It's the only block like this atm.) --- .../transform/BlockTransformExtent.java | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java index 2f5db2bef..fe577e709 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.extent.transform; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.collect.Sets; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.AbstractDelegateExtent; @@ -38,14 +36,16 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; +import java.util.HashMap; import java.util.List; -import java.util.Objects; +import java.util.Locale; +import java.util.Map; import java.util.Optional; import java.util.OptionalInt; import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nullable; +import static com.google.common.base.Preconditions.checkNotNull; /** * Transforms blocks themselves (but not their position) according to a @@ -183,22 +183,35 @@ public class BlockTransformExtent extends AbstractDelegateExtent { } } - List directionalProperties = properties.stream() - .filter(prop -> prop instanceof BooleanProperty) - .filter(prop -> directionNames.contains(prop.getName())) - .filter(property -> (Boolean) block.getState(property)) - .map(Property::getName) - .map(String::toUpperCase) - .map(Direction::valueOf) - .map(dir -> Direction.findClosest(transform.apply(dir.toVector()), Direction.Flag.CARDINAL)) - .filter(Objects::nonNull) - .map(Direction::name) - .map(String::toLowerCase) - .collect(Collectors.toList()); + Map directionalProperties = new HashMap<>(); + for (Property prop : properties) { + if (directionNames.contains(prop.getName())) { + if (prop instanceof BooleanProperty && (Boolean) block.getState(prop) + || prop instanceof EnumProperty && !block.getState(prop).toString().equals("none")) { + String origProp = prop.getName().toUpperCase(Locale.ROOT); + Direction dir = Direction.valueOf(origProp); + Direction closest = Direction.findClosest(transform.apply(dir.toVector()), Direction.Flag.CARDINAL); + if (closest != null) { + String closestProp = closest.name().toLowerCase(Locale.ROOT); + if (prop instanceof BooleanProperty) { + result = result.with((BooleanProperty) prop, Boolean.FALSE); + directionalProperties.put(closestProp, Boolean.TRUE); + } else { + if (prop.getValues().contains("none")) { + //noinspection unchecked + result = result.with((Property) prop, "none"); + } + directionalProperties.put(closestProp, block.getState(prop)); + } + } + } + } + } - if (directionalProperties.size() > 0) { + if (!directionalProperties.isEmpty()) { for (String directionName : directionNames) { - result = result.with(block.getBlockType().getProperty(directionName), directionalProperties.contains(directionName)); + Property dirProp = block.getBlockType().getProperty(directionName); + result = result.with(dirProp, directionalProperties.get(directionName)); } } From 61fd44fa8ca40ef9ff54ff3e4d5882d2e668a485 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 15 Jun 2019 20:24:47 -0400 Subject: [PATCH 210/366] Save some RAM. Vanilla only needs 12k~ states right now, 32k is unnecessary. --- .../com/sk89q/worldedit/internal/block/BlockStateIdAccess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java index 52af247c9..9b02fab98 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java @@ -51,7 +51,7 @@ public final class BlockStateIdAccess { return id < blockStates.length ? blockStates[id] : null; } - private static BlockState[] blockStates = new BlockState[2 << 14]; + private static BlockState[] blockStates = new BlockState[2 << 13]; public static void register(BlockState blockState) { OptionalInt id = getBlockStateId(blockState); From 078d6f64403eea97cfec70a0cccb8795f8dd8b75 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 9 Jun 2019 01:02:24 -0400 Subject: [PATCH 211/366] Update to Forge 1.14. --- .../worldedit/command/tool/SinglePickaxe.java | 2 - worldedit-forge/build.gradle | 10 +- .../sk89q/worldedit/forge/CommandWrapper.java | 6 +- .../sk89q/worldedit/forge/ForgeAdapter.java | 42 +-- .../worldedit/forge/ForgeBlockMaterial.java | 6 +- .../worldedit/forge/ForgeBlockRegistry.java | 3 +- .../sk89q/worldedit/forge/ForgeDataFixer.java | 349 +++++++++--------- .../sk89q/worldedit/forge/ForgeEntity.java | 6 +- .../forge/ForgeEntityProperties.java | 76 ++-- .../forge/ForgePermissionsProvider.java | 8 +- .../sk89q/worldedit/forge/ForgePlatform.java | 24 +- .../sk89q/worldedit/forge/ForgePlayer.java | 31 +- .../com/sk89q/worldedit/forge/ForgeWorld.java | 214 ++++++----- .../sk89q/worldedit/forge/ForgeWorldEdit.java | 23 +- .../com/sk89q/worldedit/forge/KeyHandler.java | 3 +- .../sk89q/worldedit/forge/NBTConverter.java | 146 ++++---- .../worldedit/forge/ThreadSafeCache.java | 6 +- .../worldedit/forge/TileEntityUtils.java | 18 +- .../worldedit/forge/WorldEditFakePlayer.java | 14 +- .../worldedit/forge/gui/GuiReferenceCard.java | 36 +- .../ResourceLocationInteractionObject.java | 65 ---- .../forge/net/handler/PacketHandlerUtil.java | 4 +- .../forge/net/handler/WECUIPacketHandler.java | 10 +- 23 files changed, 533 insertions(+), 569 deletions(-) delete mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/ResourceLocationInteractionObject.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java index 8ba789626..16721d498 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java @@ -58,8 +58,6 @@ public class SinglePickaxe implements BlockTool { player.printError("Max blocks change limit reached."); } - world.playEffect(clicked.toVector(), 2001, blockType.getLegacyId()); - return true; } diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 8b57ef74a..ab0e28fd2 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -14,8 +14,8 @@ buildscript { apply plugin: 'eclipse' apply plugin: 'net.minecraftforge.gradle' -def minecraftVersion = "1.13.2" -def forgeVersion = "25.0.146" +def minecraftVersion = "1.14.2" +def forgeVersion = "26.0.25" configurations.all { Configuration it -> it.resolutionStrategy { ResolutionStrategy rs -> @@ -36,7 +36,7 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 minecraft { - mappings channel: 'snapshot', version: '20190415-1.13.2' + mappings channel: 'snapshot', version: "20190614-${minecraftVersion}" runs { client = { @@ -57,7 +57,6 @@ minecraft { } } - accessTransformer = file('worldedit_at.cfg') } project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}" @@ -84,8 +83,7 @@ processResources { jar { manifest { attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version": version, - "FMLAT": "worldedit_at.cfg") + "WorldEdit-Version": version) } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java index 4c871e655..05d4fe5ad 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java @@ -36,7 +36,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.util.Substring; import net.minecraft.command.CommandSource; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.ServerPlayerEntity; import org.enginehub.piston.inject.InjectedValueStore; import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.MapBackedValueStore; @@ -78,8 +78,8 @@ public final class CommandWrapper { private static Predicate requirementsFor(org.enginehub.piston.Command mapping) { return ctx -> { final Entity entity = ctx.getEntity(); - if (!(entity instanceof EntityPlayerMP)) return true; - final Actor actor = ForgeAdapter.adaptPlayer(((EntityPlayerMP) entity)); + if (!(entity instanceof ServerPlayerEntity)) return true; + final Actor actor = ForgeAdapter.adaptPlayer(((ServerPlayerEntity) entity)); InjectedValueStore store = MapBackedValueStore.create(); store.injectValue(Key.of(Actor.class), context -> Optional.of(actor)); return mapping.getCondition().satisfied(store); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java index bc6448636..abcdfca29 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeAdapter.java @@ -40,15 +40,13 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.DirectionProperty; import net.minecraft.state.IProperty; import net.minecraft.state.StateContainer; -import net.minecraft.util.EnumFacing; import net.minecraft.util.IStringSerializable; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; @@ -92,20 +90,20 @@ public final class ForgeAdapter { return new Vec3d(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); } - public static EnumFacing adapt(Direction face) { + public static net.minecraft.util.Direction adapt(Direction face) { switch (face) { - case NORTH: return EnumFacing.NORTH; - case SOUTH: return EnumFacing.SOUTH; - case WEST: return EnumFacing.WEST; - case EAST: return EnumFacing.EAST; - case DOWN: return EnumFacing.DOWN; + case NORTH: return net.minecraft.util.Direction.NORTH; + case SOUTH: return net.minecraft.util.Direction.SOUTH; + case WEST: return net.minecraft.util.Direction.WEST; + case EAST: return net.minecraft.util.Direction.EAST; + case DOWN: return net.minecraft.util.Direction.DOWN; case UP: default: - return EnumFacing.UP; + return net.minecraft.util.Direction.UP; } } - public static Direction adaptEnumFacing(EnumFacing face) { + public static Direction adaptEnumFacing(net.minecraft.util.Direction face) { switch (face) { case NORTH: return Direction.NORTH; case SOUTH: return Direction.SOUTH; @@ -149,7 +147,7 @@ public final class ForgeAdapter { for (Map.Entry, Comparable> prop : mcProps.entrySet()) { Object value = prop.getValue(); if (prop.getKey() instanceof DirectionProperty) { - value = adaptEnumFacing((EnumFacing) value); + value = adaptEnumFacing((net.minecraft.util.Direction) value); } else if (prop.getKey() instanceof net.minecraft.state.EnumProperty) { value = ((IStringSerializable) value).getName(); } @@ -158,14 +156,14 @@ public final class ForgeAdapter { return props; } - private static IBlockState applyProperties(StateContainer stateContainer, IBlockState newState, Map, Object> states) { + private static net.minecraft.block.BlockState applyProperties(StateContainer stateContainer, net.minecraft.block.BlockState newState, Map, Object> states) { for (Map.Entry, Object> state : states.entrySet()) { IProperty property = stateContainer.getProperty(state.getKey().getName()); Comparable value = (Comparable) state.getValue(); // we may need to adapt this value, depending on the source prop if (property instanceof DirectionProperty) { Direction dir = (Direction) value; - value = ForgeAdapter.adapt(dir); + value = adapt(dir); } else if (property instanceof net.minecraft.state.EnumProperty) { String enumName = (String) value; value = ((net.minecraft.state.EnumProperty) property).parseValue((String) value).orElseGet(() -> { @@ -178,16 +176,16 @@ public final class ForgeAdapter { return newState; } - public static IBlockState adapt(BlockState blockState) { - Block mcBlock = ForgeAdapter.adapt(blockState.getBlockType()); - IBlockState newState = mcBlock.getDefaultState(); + public static net.minecraft.block.BlockState adapt(BlockState blockState) { + Block mcBlock = adapt(blockState.getBlockType()); + net.minecraft.block.BlockState newState = mcBlock.getDefaultState(); Map, Object> states = blockState.getStates(); return applyProperties(mcBlock.getStateContainer(), newState, states); } - public static BlockState adapt(IBlockState blockState) { + public static BlockState adapt(net.minecraft.block.BlockState blockState) { BlockType blockType = adapt(blockState.getBlock()); - return blockType.getState(ForgeAdapter.adaptProperties(blockType, blockState.getValues())); + return blockType.getState(adaptProperties(blockType, blockState.getValues())); } public static Block adapt(BlockType blockType) { @@ -207,7 +205,7 @@ public final class ForgeAdapter { } public static ItemStack adapt(BaseItemStack baseItemStack) { - NBTTagCompound forgeCompound = null; + CompoundNBT forgeCompound = null; if (baseItemStack.getNbtData() != null) { forgeCompound = NBTConverter.toNative(baseItemStack.getNbtData()); } @@ -237,7 +235,7 @@ public final class ForgeAdapter { * @param player the player * @return the WorldEdit player */ - public static ForgePlayer adaptPlayer(EntityPlayerMP player) { + public static ForgePlayer adaptPlayer(ServerPlayerEntity player) { checkNotNull(player); return new ForgePlayer(player); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java index 5f15a683b..b55b6ed7b 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockMaterial.java @@ -22,7 +22,7 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.PassthroughBlockMaterial; -import net.minecraft.block.material.EnumPushReaction; +import net.minecraft.block.material.PushReaction; import net.minecraft.block.material.Material; import javax.annotation.Nullable; @@ -63,12 +63,12 @@ public class ForgeBlockMaterial extends PassthroughBlockMaterial { @Override public boolean isFragileWhenPushed() { - return delegate.getPushReaction() == EnumPushReaction.DESTROY; + return delegate.getPushReaction() == PushReaction.DESTROY; } @Override public boolean isUnpushable() { - return delegate.getPushReaction() == EnumPushReaction.BLOCK; + return delegate.getPushReaction() == PushReaction.BLOCK; } @Override diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java index 8751fff89..614c615fd 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockRegistry.java @@ -26,7 +26,6 @@ import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BundledBlockRegistry; import net.minecraft.block.Block; import net.minecraft.block.material.Material; -import net.minecraft.block.state.IBlockState; import net.minecraft.state.IProperty; import net.minecraftforge.fml.loading.FMLLoader; @@ -77,7 +76,7 @@ public class ForgeBlockRegistry extends BundledBlockRegistry { @Override public OptionalInt getInternalBlockStateId(BlockState state) { - IBlockState equivalent = ForgeAdapter.adapt(state); + net.minecraft.block.BlockState equivalent = ForgeAdapter.adapt(state); return OptionalInt.of(Block.getStateId(equivalent)); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java index 075e70bde..23e1eb9a4 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeDataFixer.java @@ -30,27 +30,26 @@ import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.mojang.datafixers.DSL.TypeReference; -import com.mojang.datafixers.DataFixTypes; import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.DataFixerBuilder; import com.mojang.datafixers.Dynamic; import com.mojang.datafixers.schemas.Schema; import com.sk89q.jnbt.CompoundTag; -import net.minecraft.item.EnumDyeColor; -import net.minecraft.nbt.INBTBase; +import net.minecraft.item.DyeColor; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.NBTDynamicOps; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagString; -import net.minecraft.nbt.NBTTagFloat; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.JsonUtils; +import net.minecraft.nbt.StringNBT; +import net.minecraft.nbt.FloatNBT; +import net.minecraft.util.Direction; +import net.minecraft.util.JSONUtils; import net.minecraft.util.ResourceLocation; import net.minecraft.util.StringUtils; import net.minecraft.util.datafix.DataFixesManager; import net.minecraft.util.datafix.TypeReferences; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.StringTextComponent; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -104,50 +103,50 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor } private CompoundTag fixChunk(CompoundTag originalChunk, int srcVer) { - NBTTagCompound tag = NBTConverter.toNative(originalChunk); - NBTTagCompound fixed = convert(LegacyType.CHUNK, tag, srcVer); + CompoundNBT tag = NBTConverter.toNative(originalChunk); + CompoundNBT fixed = convert(LegacyType.CHUNK, tag, srcVer); return NBTConverter.fromNative(fixed); } private CompoundTag fixBlockEntity(CompoundTag origTileEnt, int srcVer) { - NBTTagCompound tag = NBTConverter.toNative(origTileEnt); - NBTTagCompound fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); + CompoundNBT tag = NBTConverter.toNative(origTileEnt); + CompoundNBT fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); return NBTConverter.fromNative(fixed); } private CompoundTag fixEntity(CompoundTag origEnt, int srcVer) { - NBTTagCompound tag = NBTConverter.toNative(origEnt); - NBTTagCompound fixed = convert(LegacyType.ENTITY, tag, srcVer); + CompoundNBT tag = NBTConverter.toNative(origEnt); + CompoundNBT fixed = convert(LegacyType.ENTITY, tag, srcVer); return NBTConverter.fromNative(fixed); } private String fixBlockState(String blockState, int srcVer) { - NBTTagCompound stateNBT = stateToNBT(blockState); - Dynamic dynamic = new Dynamic<>(OPS_NBT, stateNBT); - NBTTagCompound fixed = (NBTTagCompound) INSTANCE.fixer.update(TypeReferences.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); + CompoundNBT stateNBT = stateToNBT(blockState); + Dynamic dynamic = new Dynamic<>(OPS_NBT, stateNBT); + CompoundNBT fixed = (CompoundNBT) INSTANCE.fixer.update(TypeReferences.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); return nbtToState(fixed); } - private String nbtToState(NBTTagCompound tagCompound) { + private String nbtToState(CompoundNBT tagCompound) { StringBuilder sb = new StringBuilder(); sb.append(tagCompound.getString("Name")); if (tagCompound.contains("Properties", 10)) { sb.append('['); - NBTTagCompound props = tagCompound.getCompound("Properties"); + CompoundNBT props = tagCompound.getCompound("Properties"); sb.append(props.keySet().stream().map(k -> k + "=" + props.getString(k).replace("\"", "")).collect(Collectors.joining(","))); sb.append(']'); } return sb.toString(); } - private static NBTTagCompound stateToNBT(String blockState) { + private static CompoundNBT stateToNBT(String blockState) { int propIdx = blockState.indexOf('['); - NBTTagCompound tag = new NBTTagCompound(); + CompoundNBT tag = new CompoundNBT(); if (propIdx < 0) { tag.putString("Name", blockState); } else { tag.putString("Name", blockState.substring(0, propIdx)); - NBTTagCompound propTag = new NBTTagCompound(); + CompoundNBT propTag = new CompoundNBT(); String props = blockState.substring(propIdx + 1, blockState.length() - 1); String[] propArr = props.split(","); for (String pair : propArr) { @@ -168,8 +167,8 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor } private static String fixName(String key, int srcVer, TypeReference type) { - return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, new NBTTagString(key)), srcVer, DATA_VERSION) - .getStringValue().orElse(key); + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, new StringNBT(key)), srcVer, DATA_VERSION) + .asString().orElse(key); } private static final NBTDynamicOps OPS_NBT = NBTDynamicOps.INSTANCE; @@ -185,14 +184,14 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor private static final Map DFU_TO_LEGACY = new HashMap<>(); public enum LegacyType { - LEVEL(DataFixTypes.LEVEL), - PLAYER(DataFixTypes.PLAYER), - CHUNK(DataFixTypes.CHUNK), + LEVEL(TypeReferences.LEVEL), + PLAYER(TypeReferences.PLAYER), + CHUNK(TypeReferences.CHUNK), BLOCK_ENTITY(TypeReferences.BLOCK_ENTITY), ENTITY(TypeReferences.ENTITY), ITEM_INSTANCE(TypeReferences.ITEM_STACK), - OPTIONS(DataFixTypes.OPTIONS), - STRUCTURE(DataFixTypes.STRUCTURE); + OPTIONS(TypeReferences.OPTIONS), + STRUCTURE(TypeReferences.STRUCTURE); private final TypeReference type; @@ -206,7 +205,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor } } - public ForgeDataFixer(int dataVersion) { + ForgeDataFixer(int dataVersion) { super(dataVersion); DATA_VERSION = dataVersion; INSTANCE = this; @@ -215,8 +214,6 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor this.fixer = new WrappedDataFixer(DataFixesManager.getDataFixer()); } - - // Called after fixers are built and ready for FIXING @Override public DataFixer build(final Executor executor) { return fixer; @@ -233,7 +230,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor public Dynamic update(TypeReference type, Dynamic dynamic, int sourceVer, int targetVer) { LegacyType legacyType = DFU_TO_LEGACY.get(type.typeName()); if (sourceVer < LEGACY_VERSION && legacyType != null) { - NBTTagCompound cmp = (NBTTagCompound) dynamic.getValue(); + CompoundNBT cmp = (CompoundNBT) dynamic.getValue(); int desiredVersion = Math.min(targetVer, LEGACY_VERSION); cmp = convert(legacyType, cmp, sourceVer, desiredVersion); @@ -243,7 +240,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return realFixer.update(type, dynamic, sourceVer, targetVer); } - private NBTTagCompound convert(LegacyType type, NBTTagCompound cmp, int sourceVer, int desiredVersion) { + private CompoundNBT convert(LegacyType type, CompoundNBT cmp, int sourceVer, int desiredVersion) { List converters = ForgeDataFixer.this.converters.get(type); if (converters != null && !converters.isEmpty()) { for (DataConverter converter : converters) { @@ -270,44 +267,44 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor } } - public static NBTTagCompound convert(LegacyType type, NBTTagCompound cmp) { + public static CompoundNBT convert(LegacyType type, CompoundNBT cmp) { return convert(type.getDFUType(), cmp); } - public static NBTTagCompound convert(LegacyType type, NBTTagCompound cmp, int sourceVer) { + public static CompoundNBT convert(LegacyType type, CompoundNBT cmp, int sourceVer) { return convert(type.getDFUType(), cmp, sourceVer); } - public static NBTTagCompound convert(LegacyType type, NBTTagCompound cmp, int sourceVer, int targetVer) { + public static CompoundNBT convert(LegacyType type, CompoundNBT cmp, int sourceVer, int targetVer) { return convert(type.getDFUType(), cmp, sourceVer, targetVer); } - public static NBTTagCompound convert(TypeReference type, NBTTagCompound cmp) { + public static CompoundNBT convert(TypeReference type, CompoundNBT cmp) { int i = cmp.contains("DataVersion", 99) ? cmp.getInt("DataVersion") : -1; return convert(type, cmp, i); } - public static NBTTagCompound convert(TypeReference type, NBTTagCompound cmp, int sourceVer) { + public static CompoundNBT convert(TypeReference type, CompoundNBT cmp, int sourceVer) { return convert(type, cmp, sourceVer, DATA_VERSION); } - public static NBTTagCompound convert(TypeReference type, NBTTagCompound cmp, int sourceVer, int targetVer) { + public static CompoundNBT convert(TypeReference type, CompoundNBT cmp, int sourceVer, int targetVer) { if (sourceVer >= targetVer) { return cmp; } - return (NBTTagCompound) INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer).getValue(); + return (CompoundNBT) INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer).getValue(); } public interface DataInspector { - NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer); + CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer); } public interface DataConverter { int getDataVersion(); - NBTTagCompound convert(NBTTagCompound cmp); + CompoundNBT convert(CompoundNBT cmp); } @@ -584,19 +581,19 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return key; } - private static void convertCompound(LegacyType type, NBTTagCompound cmp, String key, int sourceVer, int targetVer) { + private static void convertCompound(LegacyType type, CompoundNBT cmp, String key, int sourceVer, int targetVer) { cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, targetVer)); } - private static void convertItem(NBTTagCompound nbttagcompound, String key, int sourceVer, int targetVer) { + private static void convertItem(CompoundNBT nbttagcompound, String key, int sourceVer, int targetVer) { if (nbttagcompound.contains(key, 10)) { convertCompound(LegacyType.ITEM_INSTANCE, nbttagcompound, key, sourceVer, targetVer); } } - private static void convertItems(NBTTagCompound nbttagcompound, String key, int sourceVer, int targetVer) { + private static void convertItems(CompoundNBT nbttagcompound, String key, int sourceVer, int targetVer) { if (nbttagcompound.contains(key, 9)) { - NBTTagList nbttaglist = nbttagcompound.getList(key, 10); + ListNBT nbttaglist = nbttagcompound.getList(key, 10); for (int j = 0; j < nbttaglist.size(); ++j) { nbttaglist.add(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompound(j), sourceVer, targetVer)); @@ -615,19 +612,19 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor } @Override - public NBTTagCompound convert(NBTTagCompound cmp) { - NBTTagList nbttaglist = cmp.getList("Equipment", 10); - NBTTagList nbttaglist1; + public CompoundNBT convert(CompoundNBT cmp) { + ListNBT nbttaglist = cmp.getList("Equipment", 10); + ListNBT nbttaglist1; if (!nbttaglist.isEmpty() && !cmp.contains("HandItems", 10)) { - nbttaglist1 = new NBTTagList(); + nbttaglist1 = new ListNBT(); nbttaglist1.add(nbttaglist.get(0)); - nbttaglist1.add(new NBTTagCompound()); + nbttaglist1.add(new CompoundNBT()); cmp.put("HandItems", nbttaglist1); } if (nbttaglist.size() > 1 && !cmp.contains("ArmorItem", 10)) { - nbttaglist1 = new NBTTagList(); + nbttaglist1 = new ListNBT(); nbttaglist1.add(nbttaglist.get(1)); nbttaglist1.add(nbttaglist.get(2)); nbttaglist1.add(nbttaglist.get(3)); @@ -638,21 +635,21 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor cmp.remove("Equipment"); if (cmp.contains("DropChances", 9)) { nbttaglist1 = cmp.getList("DropChances", 5); - NBTTagList nbttaglist2; + ListNBT nbttaglist2; if (!cmp.contains("HandDropChances", 10)) { - nbttaglist2 = new NBTTagList(); - nbttaglist2.add(new NBTTagFloat(nbttaglist1.getFloat(0))); - nbttaglist2.add(new NBTTagFloat(0.0F)); + nbttaglist2 = new ListNBT(); + nbttaglist2.add(new FloatNBT(nbttaglist1.getFloat(0))); + nbttaglist2.add(new FloatNBT(0.0F)); cmp.put("HandDropChances", nbttaglist2); } if (!cmp.contains("ArmorDropChances", 10)) { - nbttaglist2 = new NBTTagList(); - nbttaglist2.add(new NBTTagFloat(nbttaglist1.getFloat(1))); - nbttaglist2.add(new NBTTagFloat(nbttaglist1.getFloat(2))); - nbttaglist2.add(new NBTTagFloat(nbttaglist1.getFloat(3))); - nbttaglist2.add(new NBTTagFloat(nbttaglist1.getFloat(4))); + nbttaglist2 = new ListNBT(); + nbttaglist2.add(new FloatNBT(nbttaglist1.getFloat(1))); + nbttaglist2.add(new FloatNBT(nbttaglist1.getFloat(2))); + nbttaglist2.add(new FloatNBT(nbttaglist1.getFloat(3))); + nbttaglist2.add(new FloatNBT(nbttaglist1.getFloat(4))); cmp.put("ArmorDropChances", nbttaglist2); } @@ -681,14 +678,14 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor } @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { if (!cmp.contains("tag", 10)) { return cmp; } else { - NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); if (nbttagcompound1.contains("BlockEntityTag", 10)) { - NBTTagCompound nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + CompoundNBT nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); String s = cmp.getString("id"); String s1 = convertEntityId(sourceVer, s); boolean flag; @@ -812,11 +809,11 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor DataInspectorEntity() {} @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { - NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); if (nbttagcompound1.contains("EntityTag", 10)) { - NBTTagCompound nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + CompoundNBT nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); String s = cmp.getString("id"); String s1; @@ -859,7 +856,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor this.key = getKey(type); } - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { if (this.key.equals(new ResourceLocation(cmp.getString("id")))) { cmp = this.inspectChecked(cmp, sourceVer, targetVer); } @@ -867,7 +864,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return cmp; } - abstract NBTTagCompound inspectChecked(NBTTagCompound nbttagcompound, int sourceVer, int targetVer); + abstract CompoundNBT inspectChecked(CompoundNBT nbttagcompound, int sourceVer, int targetVer); } private static class DataInspectorItemList extends DataInspectorTagged { @@ -879,7 +876,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor this.keys = astring; } - NBTTagCompound inspectChecked(NBTTagCompound nbttagcompound, int sourceVer, int targetVer) { + CompoundNBT inspectChecked(CompoundNBT nbttagcompound, int sourceVer, int targetVer) { for (String s : this.keys) { ForgeDataFixer.convertItems(nbttagcompound, s, sourceVer, targetVer); } @@ -896,7 +893,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor this.keys = astring; } - NBTTagCompound inspectChecked(NBTTagCompound nbttagcompound, int sourceVer, int targetVer) { + CompoundNBT inspectChecked(CompoundNBT nbttagcompound, int sourceVer, int targetVer) { for (String key : this.keys) { ForgeDataFixer.convertItem(nbttagcompound, key, sourceVer, targetVer); } @@ -915,7 +912,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 102; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if (cmp.contains("id", 99)) { short short0 = cmp.getShort("id"); @@ -1254,7 +1251,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 147; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("ArmorStand".equals(cmp.getString("id")) && cmp.getBoolean("Silent") && !cmp.getBoolean("Marker")) { cmp.remove("Silent"); } @@ -1271,20 +1268,20 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 804; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("minecraft:banner".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); if (nbttagcompound1.contains("BlockEntityTag", 10)) { - NBTTagCompound nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + CompoundNBT nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); if (nbttagcompound2.contains("Base", 99)) { cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); if (nbttagcompound1.contains("display", 10)) { - NBTTagCompound nbttagcompound3 = nbttagcompound1.getCompound("display"); + CompoundNBT nbttagcompound3 = nbttagcompound1.getCompound("display"); if (nbttagcompound3.contains("Lore", 9)) { - NBTTagList nbttaglist = nbttagcompound3.getList("Lore", 8); + ListNBT nbttaglist = nbttagcompound3.getList("Lore", 8); if (nbttaglist.size() == 1 && "(+NBT)".equals(nbttaglist.getString(0))) { return cmp; @@ -1318,9 +1315,9 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 102; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("minecraft:potion".equals(cmp.getString("id"))) { - NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); short short0 = cmp.getShort("Damage"); if (!nbttagcompound1.contains("Potion", 8)) { @@ -1483,10 +1480,10 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 105; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("minecraft:spawn_egg".equals(cmp.getString("id"))) { - NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); - NBTTagCompound nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); + CompoundNBT nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); short short0 = cmp.getShort("Damage"); if (!nbttagcompound2.contains("id", 8)) { @@ -1589,7 +1586,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 106; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("Minecart".equals(cmp.getString("id"))) { String s = "MinecartRideable"; int i = cmp.getInt("Type"); @@ -1614,13 +1611,13 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 107; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if (!"MobSpawner".equals(cmp.getString("id"))) { return cmp; } else { if (cmp.contains("EntityId", 8)) { String s = cmp.getString("EntityId"); - NBTTagCompound nbttagcompound1 = cmp.getCompound("SpawnData"); + CompoundNBT nbttagcompound1 = cmp.getCompound("SpawnData"); nbttagcompound1.putString("id", s.isEmpty() ? "Pig" : s); cmp.put("SpawnData", nbttagcompound1); @@ -1628,13 +1625,13 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor } if (cmp.contains("SpawnPotentials", 9)) { - NBTTagList nbttaglist = cmp.getList("SpawnPotentials", 10); + ListNBT nbttaglist = cmp.getList("SpawnPotentials", 10); for (int i = 0; i < nbttaglist.size(); ++i) { - NBTTagCompound nbttagcompound2 = nbttaglist.getCompound(i); + CompoundNBT nbttagcompound2 = nbttaglist.getCompound(i); if (nbttagcompound2.contains("Type", 8)) { - NBTTagCompound nbttagcompound3 = nbttagcompound2.getCompound("Properties"); + CompoundNBT nbttagcompound3 = nbttagcompound2.getCompound("Properties"); nbttagcompound3.putString("id", nbttagcompound2.getString("Type")); nbttagcompound2.put("Entity", nbttagcompound3); @@ -1657,7 +1654,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 108; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if (cmp.contains("UUID", 8)) { cmp.putUniqueId("UUID", UUID.fromString(cmp.getString("UUID"))); } @@ -1676,7 +1673,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 109; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if (DataConverterHealth.a.contains(cmp.getString("id"))) { float f; @@ -1706,9 +1703,9 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 110; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("EntityHorse".equals(cmp.getString("id")) && !cmp.contains("SaddleItem", 10) && cmp.getBoolean("Saddle")) { - NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + CompoundNBT nbttagcompound1 = new CompoundNBT(); nbttagcompound1.putString("id", "minecraft:saddle"); nbttagcompound1.putByte("Count", (byte) 1); @@ -1729,16 +1726,16 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 111; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { String s = cmp.getString("id"); boolean flag = "Painting".equals(s); boolean flag1 = "ItemFrame".equals(s); if ((flag || flag1) && !cmp.contains("Facing", 99)) { - EnumFacing enumdirection; + Direction enumdirection; if (cmp.contains("Direction", 99)) { - enumdirection = EnumFacing.byHorizontalIndex(cmp.getByte("Direction")); + enumdirection = Direction.byHorizontalIndex(cmp.getByte("Direction")); cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getXOffset()); cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getYOffset()); cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getZOffset()); @@ -1747,7 +1744,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); } } else { - enumdirection = EnumFacing.byHorizontalIndex(cmp.getByte("Dir")); + enumdirection = Direction.byHorizontalIndex(cmp.getByte("Dir")); cmp.remove("Dir"); } @@ -1766,8 +1763,8 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 113; } - public NBTTagCompound convert(NBTTagCompound cmp) { - NBTTagList nbttaglist; + public CompoundNBT convert(CompoundNBT cmp) { + ListNBT nbttaglist; if (cmp.contains("HandDropChances", 9)) { nbttaglist = cmp.getList("HandDropChances", 5); @@ -1795,9 +1792,9 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 135; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { while (cmp.contains("Riding", 10)) { - NBTTagCompound nbttagcompound1 = this.b(cmp); + CompoundNBT nbttagcompound1 = this.b(cmp); this.convert(cmp, nbttagcompound1); cmp = nbttagcompound1; @@ -1806,15 +1803,15 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return cmp; } - protected void convert(NBTTagCompound nbttagcompound, NBTTagCompound nbttagcompound1) { - NBTTagList nbttaglist = new NBTTagList(); + protected void convert(CompoundNBT nbttagcompound, CompoundNBT nbttagcompound1) { + ListNBT nbttaglist = new ListNBT(); nbttaglist.add(nbttagcompound); nbttagcompound1.put("Passengers", nbttaglist); } - protected NBTTagCompound b(NBTTagCompound nbttagcompound) { - NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("Riding"); + protected CompoundNBT b(CompoundNBT nbttagcompound) { + CompoundNBT nbttagcompound1 = nbttagcompound.getCompound("Riding"); nbttagcompound.remove("Riding"); return nbttagcompound1; @@ -1829,12 +1826,12 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 165; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("minecraft:written_book".equals(cmp.getString("id"))) { - NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); if (nbttagcompound1.contains("pages", 9)) { - NBTTagList nbttaglist = nbttagcompound1.getList("pages", 8); + ListNBT nbttaglist = nbttagcompound1.getList("pages", 8); for (int i = 0; i < nbttaglist.size(); ++i) { String s = nbttaglist.getString(i); @@ -1842,12 +1839,12 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor if (!"null".equals(s) && !StringUtils.isNullOrEmpty(s)) { if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { - object = new TextComponentString(s); + object = new StringTextComponent(s); } else { try { - object = JsonUtils.fromJson(DataConverterSignText.a, s, ITextComponent.class, true); + object = JSONUtils.fromJson(DataConverterSignText.a, s, ITextComponent.class, true); if (object == null) { - object = new TextComponentString(""); + object = new StringTextComponent(""); } } catch (JsonParseException jsonparseexception) { ; @@ -1870,14 +1867,14 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor } if (object == null) { - object = new TextComponentString(s); + object = new StringTextComponent(s); } } } else { - object = new TextComponentString(""); + object = new StringTextComponent(""); } - nbttaglist.set(i, new NBTTagString(ITextComponent.Serializer.toJson((ITextComponent) object))); + nbttaglist.set(i, new StringNBT(ITextComponent.Serializer.toJson((ITextComponent) object))); } nbttagcompound1.put("pages", nbttaglist); @@ -1898,7 +1895,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 502; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if (cmp.contains("id", 8) && DataConverterCookedFish.a.equals(new ResourceLocation(cmp.getString("id")))) { cmp.putString("id", "minecraft:cooked_fish"); } @@ -1917,7 +1914,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 502; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("Zombie".equals(cmp.getString("id")) && cmp.getBoolean("IsVillager")) { if (!cmp.contains("ZombieType", 99)) { int i = -1; @@ -1956,7 +1953,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 505; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { cmp.putString("useVbo", "true"); return cmp; } @@ -1970,7 +1967,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 700; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("Guardian".equals(cmp.getString("id"))) { if (cmp.getBoolean("Elder")) { cmp.putString("id", "ElderGuardian"); @@ -1991,7 +1988,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 701; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { String s = cmp.getString("id"); if ("Skeleton".equals(s)) { @@ -2018,7 +2015,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 702; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("Zombie".equals(cmp.getString("id"))) { int i = cmp.getInt("ZombieType"); @@ -2053,7 +2050,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 703; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("EntityHorse".equals(cmp.getString("id"))) { int i = cmp.getInt("Type"); @@ -2097,7 +2094,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 704; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { String s = DataConverterTileEntity.a.get(cmp.getString("id")); if (s != null) { @@ -2144,7 +2141,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 704; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { String s = DataConverterEntity.a.get(cmp.getString("id")); if (s != null) { @@ -2241,11 +2238,11 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 806; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { String s = cmp.getString("id"); if ("minecraft:potion".equals(s) || "minecraft:splash_potion".equals(s) || "minecraft:lingering_potion".equals(s) || "minecraft:tipped_arrow".equals(s)) { - NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); if (!nbttagcompound1.contains("Potion", 8)) { nbttagcompound1.putString("Potion", "minecraft:water"); @@ -2268,7 +2265,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 808; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("minecraft:shulker".equals(cmp.getString("id")) && !cmp.contains("Color", 99)) { cmp.putByte("Color", (byte) 10); } @@ -2287,12 +2284,12 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 813; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.contains("tag", 10)) { - NBTTagCompound nbttagcompound1 = cmp.getCompound("tag"); + CompoundNBT nbttagcompound1 = cmp.getCompound("tag"); if (nbttagcompound1.contains("BlockEntityTag", 10)) { - NBTTagCompound nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + CompoundNBT nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); if (nbttagcompound2.getList("Items", 10).isEmpty()) { nbttagcompound2.remove("Items"); @@ -2325,7 +2322,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 813; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("minecraft:shulker".equals(cmp.getString("id"))) { cmp.remove("Color"); } @@ -2342,7 +2339,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 816; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if (cmp.contains("lang", 8)) { cmp.putString("lang", cmp.getString("lang").toLowerCase(Locale.ROOT)); } @@ -2359,7 +2356,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 820; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("minecraft:totem".equals(cmp.getString("id"))) { cmp.putString("id", "minecraft:totem_of_undying"); } @@ -2378,18 +2375,18 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 1125; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { boolean flag = true; try { - NBTTagCompound nbttagcompound1 = cmp.getCompound("Level"); + CompoundNBT nbttagcompound1 = cmp.getCompound("Level"); int i = nbttagcompound1.getInt("xPos"); int j = nbttagcompound1.getInt("zPos"); - NBTTagList nbttaglist = nbttagcompound1.getList("TileEntities", 10); - NBTTagList nbttaglist1 = nbttagcompound1.getList("Sections", 10); + ListNBT nbttaglist = nbttagcompound1.getList("TileEntities", 10); + ListNBT nbttaglist1 = nbttagcompound1.getList("Sections", 10); for (int k = 0; k < nbttaglist1.size(); ++k) { - NBTTagCompound nbttagcompound2 = nbttaglist1.getCompound(k); + CompoundNBT nbttagcompound2 = nbttaglist1.getCompound(k); byte b0 = nbttagcompound2.getByte("Y"); byte[] abyte = nbttagcompound2.getByteArray("Blocks"); @@ -2398,7 +2395,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor int i1 = l & 15; int j1 = l >> 8 & 15; int k1 = l >> 4 & 15; - NBTTagCompound nbttagcompound3 = new NBTTagCompound(); + CompoundNBT nbttagcompound3 = new CompoundNBT(); nbttagcompound3.putString("id", "bed"); nbttagcompound3.putInt("x", i1 + (i << 4)); @@ -2424,9 +2421,9 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 1125; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { - cmp.putShort("Damage", (short) EnumDyeColor.RED.getId()); + cmp.putShort("Damage", (short) DyeColor.RED.getId()); } return cmp; @@ -2438,7 +2435,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor public static final Gson a = new GsonBuilder().registerTypeAdapter(ITextComponent.class, new JsonDeserializer() { ITextComponent a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { if (jsonelement.isJsonPrimitive()) { - return new TextComponentString(jsonelement.getAsString()); + return new StringTextComponent(jsonelement.getAsString()); } else if (jsonelement.isJsonArray()) { JsonArray jsonarray = jsonelement.getAsJsonArray(); ITextComponent iTextComponent = null; @@ -2472,7 +2469,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return 101; } - public NBTTagCompound convert(NBTTagCompound cmp) { + public CompoundNBT convert(CompoundNBT cmp) { if ("Sign".equals(cmp.getString("id"))) { this.convert(cmp, "Text1"); this.convert(cmp, "Text2"); @@ -2483,18 +2480,18 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor return cmp; } - private void convert(NBTTagCompound nbttagcompound, String s) { + private void convert(CompoundNBT nbttagcompound, String s) { String s1 = nbttagcompound.getString(s); Object object = null; if (!"null".equals(s1) && !StringUtils.isNullOrEmpty(s1)) { if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { - object = new TextComponentString(s1); + object = new StringTextComponent(s1); } else { try { - object = JsonUtils.fromJson(DataConverterSignText.a, s1, ITextComponent.class, true); + object = JSONUtils.fromJson(DataConverterSignText.a, s1, ITextComponent.class, true); if (object == null) { - object = new TextComponentString(""); + object = new StringTextComponent(""); } } catch (JsonParseException jsonparseexception) { ; @@ -2517,11 +2514,11 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor } if (object == null) { - object = new TextComponentString(s1); + object = new StringTextComponent(s1); } } } else { - object = new TextComponentString(""); + object = new StringTextComponent(""); } nbttagcompound.putString(s, ITextComponent.Serializer.toJson((ITextComponent) object)); @@ -2530,9 +2527,9 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor private static class DataInspectorPlayerVehicle implements DataInspector { @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { if (cmp.contains("RootVehicle", 10)) { - NBTTagCompound nbttagcompound1 = cmp.getCompound("RootVehicle"); + CompoundNBT nbttagcompound1 = cmp.getCompound("RootVehicle"); if (nbttagcompound1.contains("Entity", 10)) { convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); @@ -2545,7 +2542,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor private static class DataInspectorLevelPlayer implements DataInspector { @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { if (cmp.contains("Player", 10)) { convertCompound(LegacyType.PLAYER, cmp, "Player", sourceVer, targetVer); } @@ -2556,16 +2553,16 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor private static class DataInspectorStructure implements DataInspector { @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { - NBTTagList nbttaglist; + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { + ListNBT nbttaglist; int j; - NBTTagCompound nbttagcompound1; + CompoundNBT nbttagcompound1; if (cmp.contains("entities", 9)) { nbttaglist = cmp.getList("entities", 10); for (j = 0; j < nbttaglist.size(); ++j) { - nbttagcompound1 = (NBTTagCompound) nbttaglist.get(j); + nbttagcompound1 = (CompoundNBT) nbttaglist.get(j); if (nbttagcompound1.contains("nbt", 10)) { convertCompound(LegacyType.ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); } @@ -2576,7 +2573,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor nbttaglist = cmp.getList("blocks", 10); for (j = 0; j < nbttaglist.size(); ++j) { - nbttagcompound1 = (NBTTagCompound) nbttaglist.get(j); + nbttagcompound1 = (CompoundNBT) nbttaglist.get(j); if (nbttagcompound1.contains("nbt", 10)) { convertCompound(LegacyType.BLOCK_ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); } @@ -2589,17 +2586,17 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor private static class DataInspectorChunks implements DataInspector { @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { if (cmp.contains("Level", 10)) { - NBTTagCompound nbttagcompound1 = cmp.getCompound("Level"); - NBTTagList nbttaglist; + CompoundNBT nbttagcompound1 = cmp.getCompound("Level"); + ListNBT nbttaglist; int j; if (nbttagcompound1.contains("Entities", 9)) { nbttaglist = nbttagcompound1.getList("Entities", 10); for (j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.ENTITY, (NBTTagCompound) nbttaglist.get(j), sourceVer, targetVer)); + nbttaglist.set(j, convert(LegacyType.ENTITY, (CompoundNBT) nbttaglist.get(j), sourceVer, targetVer)); } } @@ -2607,7 +2604,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor nbttaglist = nbttagcompound1.getList("TileEntities", 10); for (j = 0; j < nbttaglist.size(); ++j) { - nbttaglist.set(j, convert(LegacyType.BLOCK_ENTITY, (NBTTagCompound) nbttaglist.get(j), sourceVer, targetVer)); + nbttaglist.set(j, convert(LegacyType.BLOCK_ENTITY, (CompoundNBT) nbttaglist.get(j), sourceVer, targetVer)); } } } @@ -2618,9 +2615,9 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor private static class DataInspectorEntityPassengers implements DataInspector { @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { if (cmp.contains("Passengers", 9)) { - NBTTagList nbttaglist = cmp.getList("Passengers", 10); + ListNBT nbttaglist = cmp.getList("Passengers", 10); for (int j = 0; j < nbttaglist.size(); ++j) { nbttaglist.set(j, convert(LegacyType.ENTITY, nbttaglist.getCompound(j), sourceVer, targetVer)); @@ -2633,7 +2630,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor private static class DataInspectorPlayer implements DataInspector { @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { convertItems(cmp, "Inventory", sourceVer, targetVer); convertItems(cmp, "EnderItems", sourceVer, targetVer); if (cmp.contains("ShoulderEntityLeft", 10)) { @@ -2652,15 +2649,15 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor ResourceLocation entityVillager = getKey("EntityVillager"); @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { if (entityVillager.equals(new ResourceLocation(cmp.getString("id"))) && cmp.contains("Offers", 10)) { - NBTTagCompound nbttagcompound1 = cmp.getCompound("Offers"); + CompoundNBT nbttagcompound1 = cmp.getCompound("Offers"); if (nbttagcompound1.contains("Recipes", 9)) { - NBTTagList nbttaglist = nbttagcompound1.getList("Recipes", 10); + ListNBT nbttaglist = nbttagcompound1.getList("Recipes", 10); for (int j = 0; j < nbttaglist.size(); ++j) { - NBTTagCompound nbttagcompound2 = nbttaglist.getCompound(j); + CompoundNBT nbttagcompound2 = nbttaglist.getCompound(j); convertItem(nbttagcompound2, "buy", sourceVer, targetVer); convertItem(nbttagcompound2, "buyB", sourceVer, targetVer); @@ -2679,7 +2676,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { String s = cmp.getString("id"); if (entityMinecartMobSpawner.equals(new ResourceLocation(s))) { cmp.putString("id", tileEntityMobSpawner.toString()); @@ -2695,13 +2692,13 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor ResourceLocation tileEntityMobSpawner = getKey("TileEntityMobSpawner"); @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { if (tileEntityMobSpawner.equals(new ResourceLocation(cmp.getString("id")))) { if (cmp.contains("SpawnPotentials", 9)) { - NBTTagList nbttaglist = cmp.getList("SpawnPotentials", 10); + ListNBT nbttaglist = cmp.getList("SpawnPotentials", 10); for (int j = 0; j < nbttaglist.size(); ++j) { - NBTTagCompound nbttagcompound1 = nbttaglist.getCompound(j); + CompoundNBT nbttagcompound1 = nbttaglist.getCompound(j); convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); } @@ -2718,7 +2715,7 @@ class ForgeDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wor ResourceLocation tileEntityCommand = getKey("TileEntityCommand"); @Override - public NBTTagCompound inspect(NBTTagCompound cmp, int sourceVer, int targetVer) { + public CompoundNBT inspect(CompoundNBT cmp, int sourceVer, int targetVer) { if (tileEntityCommand.equals(new ResourceLocation(cmp.getString("id")))) { cmp.putString("id", "Control"); convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java index 96e97cf29..a7f99e1a7 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntity.java @@ -29,7 +29,7 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.entity.EntityTypes; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.ResourceLocation; import java.lang.ref.WeakReference; @@ -51,7 +51,7 @@ class ForgeEntity implements Entity { if (entity != null) { ResourceLocation id = entity.getType().getRegistryName(); if (id != null) { - NBTTagCompound tag = new NBTTagCompound(); + CompoundNBT tag = new CompoundNBT(); entity.writeWithoutTypeId(tag); return new BaseEntity(EntityTypes.get(id.toString()), NBTConverter.fromNative(tag)); } else { @@ -78,7 +78,7 @@ class ForgeEntity implements Entity { @Override public boolean setLocation(Location location) { - // TODO + // TODO unused atm return false; } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java index 6e07e18ad..7cbfd469d 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeEntityProperties.java @@ -23,27 +23,27 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.entity.metadata.EntityProperties; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLiving; -import net.minecraft.entity.IMerchant; -import net.minecraft.entity.INpc; +import net.minecraft.entity.boss.dragon.EnderDragonPartEntity; +import net.minecraft.entity.item.ArmorStandEntity; +import net.minecraft.entity.item.ExperienceOrbEntity; +import net.minecraft.entity.item.PaintingEntity; +import net.minecraft.entity.item.TNTEntity; +import net.minecraft.entity.merchant.IMerchant; +import net.minecraft.entity.INPC; import net.minecraft.entity.IProjectile; -import net.minecraft.entity.MultiPartEntityPart; -import net.minecraft.entity.item.EntityArmorStand; -import net.minecraft.entity.item.EntityBoat; -import net.minecraft.entity.item.EntityEnderEye; -import net.minecraft.entity.item.EntityFallingBlock; -import net.minecraft.entity.item.EntityItem; -import net.minecraft.entity.item.EntityItemFrame; -import net.minecraft.entity.item.EntityMinecart; -import net.minecraft.entity.item.EntityPainting; -import net.minecraft.entity.item.EntityTNTPrimed; -import net.minecraft.entity.item.EntityXPOrb; -import net.minecraft.entity.monster.EntityGolem; -import net.minecraft.entity.passive.EntityAmbientCreature; -import net.minecraft.entity.passive.EntityAnimal; -import net.minecraft.entity.passive.EntityTameable; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.MobEntity; +import net.minecraft.entity.item.BoatEntity; +import net.minecraft.entity.item.EyeOfEnderEntity; +import net.minecraft.entity.item.FallingBlockEntity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.entity.item.ItemFrameEntity; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.passive.AmbientEntity; +import net.minecraft.entity.passive.AnimalEntity; +import net.minecraft.entity.passive.TameableEntity; +import net.minecraft.entity.passive.GolemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; public class ForgeEntityProperties implements EntityProperties { @@ -56,82 +56,82 @@ public class ForgeEntityProperties implements EntityProperties { @Override public boolean isPlayerDerived() { - return entity instanceof EntityPlayer; + return entity instanceof PlayerEntity; } @Override public boolean isProjectile() { - return entity instanceof EntityEnderEye || entity instanceof IProjectile; + return entity instanceof EyeOfEnderEntity || entity instanceof IProjectile; } @Override public boolean isItem() { - return entity instanceof EntityItem; + return entity instanceof ItemEntity; } @Override public boolean isFallingBlock() { - return entity instanceof EntityFallingBlock; + return entity instanceof FallingBlockEntity; } @Override public boolean isPainting() { - return entity instanceof EntityPainting; + return entity instanceof PaintingEntity; } @Override public boolean isItemFrame() { - return entity instanceof EntityItemFrame; + return entity instanceof ItemFrameEntity; } @Override public boolean isBoat() { - return entity instanceof EntityBoat; + return entity instanceof BoatEntity; } @Override public boolean isMinecart() { - return entity instanceof EntityMinecart; + return entity instanceof AbstractMinecartEntity; } @Override public boolean isTNT() { - return entity instanceof EntityTNTPrimed; + return entity instanceof TNTEntity; } @Override public boolean isExperienceOrb() { - return entity instanceof EntityXPOrb; + return entity instanceof ExperienceOrbEntity; } @Override public boolean isLiving() { - return entity instanceof EntityLiving; + return entity instanceof MobEntity; } @Override public boolean isAnimal() { - return entity instanceof EntityAnimal; + return entity instanceof AnimalEntity; } @Override public boolean isAmbient() { - return entity instanceof EntityAmbientCreature; + return entity instanceof AmbientEntity; } @Override public boolean isNPC() { - return entity instanceof INpc || entity instanceof IMerchant; + return entity instanceof INPC || entity instanceof IMerchant; } @Override public boolean isGolem() { - return entity instanceof EntityGolem; + return entity instanceof GolemEntity; } @Override public boolean isTamed() { - return entity instanceof EntityTameable && ((EntityTameable) entity).isTamed(); + return entity instanceof TameableEntity && ((TameableEntity) entity).isTamed(); } @Override @@ -141,11 +141,11 @@ public class ForgeEntityProperties implements EntityProperties { @Override public boolean isArmorStand() { - return entity instanceof EntityArmorStand; + return entity instanceof ArmorStandEntity; } @Override public boolean isPasteable() { - return !(entity instanceof EntityPlayerMP || entity instanceof MultiPartEntityPart); + return !(entity instanceof ServerPlayerEntity || entity instanceof EnderDragonPartEntity); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java index 6129cb31b..767d32615 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePermissionsProvider.java @@ -19,13 +19,13 @@ package com.sk89q.worldedit.forge; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.world.GameType; import net.minecraftforge.fml.server.ServerLifecycleHooks; public interface ForgePermissionsProvider { - boolean hasPermission(EntityPlayerMP player, String permission); + boolean hasPermission(ServerPlayerEntity player, String permission); void registerPermission(String permission); @@ -38,7 +38,7 @@ public interface ForgePermissionsProvider { } @Override - public boolean hasPermission(EntityPlayerMP player, String permission) { + public boolean hasPermission(ServerPlayerEntity player, String permission) { ForgeConfiguration configuration = platform.getConfiguration(); return configuration.cheatMode || ServerLifecycleHooks.getCurrentServer().getPlayerList().canSendCommands(player.getGameProfile()) || @@ -49,7 +49,7 @@ public interface ForgePermissionsProvider { public void registerPermission(String permission) {} } - // TODO Re-add when Sponge for 1.13 is out + // TODO Re-add when Sponge for 1.14 is out // class SpongePermissionsProvider implements ForgePermissionsProvider { // // @Override diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 1a3958d55..99ef0103e 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -30,11 +30,12 @@ import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; import net.minecraft.command.Commands; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.PlayerList; import net.minecraft.util.ResourceLocation; -import net.minecraft.world.WorldServer; +import net.minecraft.util.SharedConstants; +import net.minecraft.world.ServerWorld; import net.minecraftforge.fml.server.ServerLifecycleHooks; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; @@ -74,8 +75,7 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { @Override public int getDataVersion() { - // TODO switch to SharedConstants in 1.14 - return 1631; + return SharedConstants.getVersion().getWorldVersion(); } @Override @@ -99,10 +99,10 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { } @Override - public List getWorlds() { - Iterable worlds = server.getWorlds(); - List ret = new ArrayList<>(); - for (WorldServer world : worlds) { + public List getWorlds() { + Iterable worlds = server.getWorlds(); + List ret = new ArrayList<>(); + for (ServerWorld world : worlds) { ret.add(new ForgeWorld(world)); } return ret; @@ -114,7 +114,7 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { if (player instanceof ForgePlayer) { return player; } else { - EntityPlayerMP entity = server.getPlayerList().getPlayerByUsername(player.getName()); + ServerPlayerEntity entity = server.getPlayerList().getPlayerByUsername(player.getName()); return entity != null ? new ForgePlayer(entity) : null; } } @@ -125,7 +125,7 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { if (world instanceof ForgeWorld) { return world; } else { - for (WorldServer ws : server.getWorlds()) { + for (ServerWorld ws : server.getWorlds()) { if (ws.getWorldInfo().getWorldName().equals(world.getName())) { return new ForgeWorld(ws); } @@ -145,7 +145,7 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { Set perms = command.getCondition().as(PermissionCondition.class) .map(PermissionCondition::getPermissions) .orElseGet(Collections::emptySet); - if (perms.size() > 0) { + if (!perms.isEmpty()) { perms.forEach(ForgeWorldEdit.inst.getPermissionsProvider()::registerPermission); } } @@ -193,7 +193,7 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { public Collection getConnectedUsers() { List users = new ArrayList<>(); PlayerList scm = server.getPlayerList(); - for (EntityPlayerMP entity : scm.getPlayers()) { + for (ServerPlayerEntity entity : scm.getPlayers()) { if (entity != null) { users.add(new ForgePlayer(entity)); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index 3d6335e46..37f1a67ff 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -40,17 +40,17 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import io.netty.buffer.Unpooled; import net.minecraft.block.Block; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.network.PacketBuffer; -import net.minecraft.network.play.server.SPacketBlockChange; -import net.minecraft.network.play.server.SPacketCustomPayload; -import net.minecraft.network.play.server.SPacketUpdateTileEntity; -import net.minecraft.util.EnumHand; +import net.minecraft.network.play.server.SChangeBlockPacket; +import net.minecraft.network.play.server.SCustomPayloadPlayPacket; +import net.minecraft.network.play.server.SUpdateTileEntityPacket; +import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; import java.io.IOException; @@ -60,10 +60,11 @@ import javax.annotation.Nullable; public class ForgePlayer extends AbstractPlayerActor { + // see ClientPlayNetHandler: search for "invalid update packet", lots of hardcoded consts private static final int STRUCTURE_BLOCK_PACKET_ID = 7; - private final EntityPlayerMP player; + private final ServerPlayerEntity player; - protected ForgePlayer(EntityPlayerMP player) { + protected ForgePlayer(ServerPlayerEntity player) { this.player = player; ThreadSafeCache.getInstance().getOnlineIds().add(getUniqueId()); } @@ -75,7 +76,7 @@ public class ForgePlayer extends AbstractPlayerActor { @Override public BaseItemStack getItemInHand(HandSide handSide) { - ItemStack is = this.player.getHeldItem(handSide == HandSide.MAIN_HAND ? EnumHand.MAIN_HAND : EnumHand.OFF_HAND); + ItemStack is = this.player.getHeldItem(handSide == HandSide.MAIN_HAND ? Hand.MAIN_HAND : Hand.OFF_HAND); return ForgeAdapter.adapt(is); } @@ -123,14 +124,14 @@ public class ForgePlayer extends AbstractPlayerActor { send = send + "|" + StringUtil.joinString(params, "|"); } PacketBuffer buffer = new PacketBuffer(Unpooled.copiedBuffer(send.getBytes(WECUIPacketHandler.UTF_8_CHARSET))); - SPacketCustomPayload packet = new SPacketCustomPayload(new ResourceLocation(ForgeWorldEdit.CUI_PLUGIN_CHANNEL), buffer); + SCustomPayloadPlayPacket packet = new SCustomPayloadPlayPacket(new ResourceLocation(ForgeWorldEdit.CUI_PLUGIN_CHANNEL), buffer); this.player.connection.sendPacket(packet); } @Override public void printRaw(String msg) { for (String part : msg.split("\n")) { - this.player.sendMessage(new TextComponentString(part)); + this.player.sendMessage(new StringTextComponent(part)); } } @@ -156,7 +157,7 @@ public class ForgePlayer extends AbstractPlayerActor { private void sendColorized(String msg, TextFormatting formatting) { for (String part : msg.split("\n")) { - TextComponentString component = new TextComponentString(part); + StringTextComponent component = new StringTextComponent(part); component.getStyle().setColor(formatting); this.player.sendMessage(component); } @@ -196,10 +197,10 @@ public class ForgePlayer extends AbstractPlayerActor { } BlockPos loc = ForgeAdapter.toBlockPos(pos); if (block == null) { - final SPacketBlockChange packetOut = new SPacketBlockChange(((ForgeWorld) world).getWorld(), loc); + final SChangeBlockPacket packetOut = new SChangeBlockPacket(((ForgeWorld) world).getWorld(), loc); player.connection.sendPacket(packetOut); } else { - final SPacketBlockChange packetOut = new SPacketBlockChange(); + final SChangeBlockPacket packetOut = new SChangeBlockPacket(); PacketBuffer buf = new PacketBuffer(Unpooled.buffer()); buf.writeBlockPos(loc); buf.writeVarInt(Block.getStateId(ForgeAdapter.adapt(block.toImmutableState()))); @@ -213,7 +214,7 @@ public class ForgePlayer extends AbstractPlayerActor { final BaseBlock baseBlock = (BaseBlock) block; final CompoundTag nbtData = baseBlock.getNbtData(); if (nbtData != null) { - player.connection.sendPacket(new SPacketUpdateTileEntity( + player.connection.sendPacket(new SUpdateTileEntityPacket( new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), STRUCTURE_BLOCK_PACKET_ID, NBTConverter.toNative(nbtData)) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index f0c00dd45..3c2d374b4 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -50,34 +50,37 @@ import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherTypes; import net.minecraft.block.Block; -import net.minecraft.block.BlockLeaves; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.LeavesBlock; import net.minecraft.entity.EntityType; -import net.minecraft.entity.item.EntityItem; -import net.minecraft.init.Blocks; +import net.minecraft.entity.item.ItemEntity; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.ResourceLocation; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.ServerWorld; import net.minecraft.world.World; -import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.AbstractChunkProvider; import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.IChunkProvider; -import net.minecraft.world.chunk.storage.AnvilSaveHandler; -import net.minecraft.world.gen.ChunkProviderServer; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.chunk.ServerChunkProvider; +import net.minecraft.world.chunk.listener.IChunkStatusListener; import net.minecraft.world.gen.feature.BigBrownMushroomFeature; +import net.minecraft.world.gen.feature.BigMushroomFeatureConfig; import net.minecraft.world.gen.feature.BigRedMushroomFeature; import net.minecraft.world.gen.feature.BigTreeFeature; import net.minecraft.world.gen.feature.BirchTreeFeature; -import net.minecraft.world.gen.feature.CanopyTreeFeature; +import net.minecraft.world.gen.feature.DarkOakTreeFeature; import net.minecraft.world.gen.feature.Feature; +import net.minecraft.world.gen.feature.IFeatureConfig; import net.minecraft.world.gen.feature.JungleTreeFeature; import net.minecraft.world.gen.feature.MegaJungleFeature; import net.minecraft.world.gen.feature.MegaPineTree; @@ -88,17 +91,20 @@ import net.minecraft.world.gen.feature.ShrubFeature; import net.minecraft.world.gen.feature.SwampTreeFeature; import net.minecraft.world.gen.feature.TallTaigaTreeFeature; import net.minecraft.world.gen.feature.TreeFeature; +import net.minecraft.world.storage.SaveHandler; import net.minecraft.world.storage.WorldInfo; import javax.annotation.Nullable; import java.io.File; import java.lang.ref.WeakReference; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.OptionalInt; import java.util.Random; import java.util.concurrent.ExecutionException; import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -110,9 +116,9 @@ public class ForgeWorld extends AbstractWorld { private static final Random random = new Random(); private static final int UPDATE = 1, NOTIFY = 2; - private static final IBlockState JUNGLE_LOG = Blocks.JUNGLE_LOG.getDefaultState(); - private static final IBlockState JUNGLE_LEAF = Blocks.JUNGLE_LEAVES.getDefaultState().with(BlockLeaves.PERSISTENT, Boolean.TRUE); - private static final IBlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(BlockLeaves.PERSISTENT, Boolean.TRUE); + private static final net.minecraft.block.BlockState JUNGLE_LOG = Blocks.JUNGLE_LOG.getDefaultState(); + private static final net.minecraft.block.BlockState JUNGLE_LEAF = Blocks.JUNGLE_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE); + private static final net.minecraft.block.BlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE); private final WeakReference worldRef; @@ -174,10 +180,10 @@ public class ForgeWorld extends AbstractWorld { // First set the block Chunk chunk = world.getChunk(x >> 4, z >> 4); BlockPos pos = new BlockPos(x, y, z); - IBlockState old = chunk.getBlockState(pos); + net.minecraft.block.BlockState old = chunk.getBlockState(pos); OptionalInt stateId = BlockStateIdAccess.getBlockStateId(block.toImmutableState()); - IBlockState newState = stateId.isPresent() ? Block.getStateById(stateId.getAsInt()) : ForgeAdapter.adapt(block.toImmutableState()); - IBlockState successState = chunk.setBlockState(pos, newState, false); + net.minecraft.block.BlockState newState = stateId.isPresent() ? Block.getStateById(stateId.getAsInt()) : ForgeAdapter.adapt(block.toImmutableState()); + net.minecraft.block.BlockState successState = chunk.setBlockState(pos, newState, false); boolean successful = successState != null; // Create the TileEntity @@ -185,15 +191,16 @@ public class ForgeWorld extends AbstractWorld { if (block instanceof BaseBlock) { CompoundTag tag = ((BaseBlock) block).getNbtData(); if (tag != null) { - NBTTagCompound nativeTag = NBTConverter.toNative(tag); + CompoundNBT nativeTag = NBTConverter.toNative(tag); nativeTag.putString("id", ((BaseBlock) block).getNbtId()); TileEntityUtils.setTileEntity(world, position, nativeTag); + successful = true; // update if TE changed as well } } } if (successful && notifyAndLight) { - world.checkLight(pos); + world.getChunkProvider().getLightManager().checkBlock(pos); world.markAndNotifyBlock(pos, chunk, old, newState, UPDATE | NOTIFY); } @@ -239,45 +246,44 @@ public class ForgeWorld extends AbstractWorld { checkNotNull(position); checkNotNull(biome); - Chunk chunk = getWorld().getChunk(new BlockPos(position.getBlockX(), 0, position.getBlockZ())); - if (chunk.isLoaded()) { - chunk.getBiomes()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = ForgeAdapter.adapt(biome); - return true; + IChunk chunk = getWorld().getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4, ChunkStatus.FULL, false); + if (chunk == null) { + return false; } - - return false; + chunk.getBiomes()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = ForgeAdapter.adapt(biome); + return true; } - private static LoadingCache fakePlayers + private static LoadingCache fakePlayers = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(WorldEditFakePlayer::new)); @Override public boolean useItem(BlockVector3 position, BaseItem item, Direction face) { ItemStack stack = ForgeAdapter.adapt(new BaseItemStack(item.getType(), item.getNbtData(), 1)); - WorldServer world = (WorldServer) getWorld(); + ServerWorld world = (ServerWorld) getWorld(); final WorldEditFakePlayer fakePlayer; try { fakePlayer = fakePlayers.get(world); } catch (ExecutionException ignored) { return false; } - fakePlayer.setHeldItem(EnumHand.MAIN_HAND, stack); + fakePlayer.setHeldItem(Hand.MAIN_HAND, stack); fakePlayer.setLocationAndAngles(position.getBlockX(), position.getBlockY(), position.getBlockZ(), (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); final BlockPos blockPos = ForgeAdapter.toBlockPos(position); - final EnumFacing enumFacing = ForgeAdapter.adapt(face); - ItemUseContext itemUseContext = new ItemUseContext(fakePlayer, stack, blockPos, enumFacing, blockPos.getX(), blockPos.getY(), blockPos.getZ()); - EnumActionResult used = stack.onItemUse(itemUseContext); - if (used != EnumActionResult.SUCCESS) { + final BlockRayTraceResult rayTraceResult = new BlockRayTraceResult(ForgeAdapter.toVec3(position), + ForgeAdapter.adapt(face), blockPos, false); + ItemUseContext itemUseContext = new ItemUseContext(fakePlayer, Hand.MAIN_HAND, rayTraceResult); + ActionResultType used = stack.onItemUse(itemUseContext); + if (used != ActionResultType.SUCCESS) { // try activating the block - if (getWorld().getBlockState(blockPos).onBlockActivated(world, blockPos, fakePlayer, EnumHand.MAIN_HAND, - enumFacing, blockPos.getX(), blockPos.getY(), blockPos.getZ())) { - used = EnumActionResult.SUCCESS; + if (getWorld().getBlockState(blockPos).onBlockActivated(world, fakePlayer, Hand.MAIN_HAND, rayTraceResult)) { + used = ActionResultType.SUCCESS; } else { - used = stack.getItem().onItemRightClick(world, fakePlayer, EnumHand.MAIN_HAND).getType(); + used = stack.getItem().onItemRightClick(world, fakePlayer, Hand.MAIN_HAND).getType(); } } - return used == EnumActionResult.SUCCESS; + return used == ActionResultType.SUCCESS; } @Override @@ -289,24 +295,22 @@ public class ForgeWorld extends AbstractWorld { return; } - EntityItem entity = new EntityItem(getWorld(), position.getX(), position.getY(), position.getZ(), ForgeAdapter.adapt(item)); + ItemEntity entity = new ItemEntity(getWorld(), position.getX(), position.getY(), position.getZ(), ForgeAdapter.adapt(item)); entity.setPickupDelay(10); - getWorld().spawnEntity(entity); + getWorld().addEntity(entity); } @Override public void simulateBlockMine(BlockVector3 position) { BlockPos pos = ForgeAdapter.toBlockPos(position); - IBlockState state = getWorld().getBlockState(pos); - state.dropBlockAsItem(getWorld(), pos, 0); - getWorld().removeBlock(pos); + getWorld().destroyBlock(pos, true); } @Override public boolean regenerate(Region region, EditSession editSession) { // Don't even try to regen if it's going to fail. - IChunkProvider provider = getWorld().getChunkProvider(); - if (!(provider instanceof ChunkProviderServer)) { + AbstractChunkProvider provider = getWorld().getChunkProvider(); + if (!(provider instanceof ServerChunkProvider)) { return false; } @@ -315,11 +319,12 @@ public class ForgeWorld extends AbstractWorld { // normally it should be deleted at the end of this method saveFolder.deleteOnExit(); try { - WorldServer originalWorld = (WorldServer) getWorld(); + ServerWorld originalWorld = (ServerWorld) getWorld(); MinecraftServer server = originalWorld.getServer(); - AnvilSaveHandler saveHandler = new AnvilSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); - World freshWorld = new WorldServer(server, saveHandler, originalWorld.getSavedDataStorage(), originalWorld.getWorldInfo(), originalWorld.dimension.getType(), originalWorld.profiler).init(); + SaveHandler saveHandler = new SaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); + World freshWorld = new ServerWorld(server, server.getBackgroundExecutor(), saveHandler, originalWorld.getWorldInfo(), + originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener()); // Pre-gen all the chunks // We need to also pull one more chunk in every direction @@ -342,36 +347,45 @@ public class ForgeWorld extends AbstractWorld { } @Nullable - private static Feature createTreeFeatureGenerator(TreeType type) { + private static Feature createTreeFeatureGenerator(TreeType type) { switch (type) { - case TREE: return new TreeFeature(true); - case BIG_TREE: return new BigTreeFeature(true); - case PINE: - case REDWOOD: return new PointyTaigaTreeFeature(); - case TALL_REDWOOD: return new TallTaigaTreeFeature(true); - case BIRCH: return new BirchTreeFeature(true, false); - case JUNGLE: return new MegaJungleFeature(true, 10, 20, JUNGLE_LOG, JUNGLE_LEAF); - case SMALL_JUNGLE: return new JungleTreeFeature(true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, false); - case SHORT_JUNGLE: return new JungleTreeFeature(true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, true); - case JUNGLE_BUSH: return new ShrubFeature(JUNGLE_LOG, JUNGLE_SHRUB); - case RED_MUSHROOM: return new BigBrownMushroomFeature(); - case BROWN_MUSHROOM: return new BigRedMushroomFeature(); - case SWAMP: return new SwampTreeFeature(); - case ACACIA: return new SavannaTreeFeature(true); - case DARK_OAK: return new CanopyTreeFeature(true); - case MEGA_REDWOOD: return new MegaPineTree(false, random.nextBoolean()); - case TALL_BIRCH: return new BirchTreeFeature(true, true); + case TREE: return new TreeFeature(NoFeatureConfig::deserialize, true); + case BIG_TREE: return new BigTreeFeature(NoFeatureConfig::deserialize, true); + case REDWOOD: return new PointyTaigaTreeFeature(NoFeatureConfig::deserialize); + case TALL_REDWOOD: return new TallTaigaTreeFeature(NoFeatureConfig::deserialize, true); + case BIRCH: return new BirchTreeFeature(NoFeatureConfig::deserialize, true, false); + case JUNGLE: return new MegaJungleFeature(NoFeatureConfig::deserialize, true, 10, 20, JUNGLE_LOG, JUNGLE_LEAF); + case SMALL_JUNGLE: return new JungleTreeFeature(NoFeatureConfig::deserialize, true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, false); + case SHORT_JUNGLE: return new JungleTreeFeature(NoFeatureConfig::deserialize, true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, true); + case JUNGLE_BUSH: return new ShrubFeature(NoFeatureConfig::deserialize, JUNGLE_LOG, JUNGLE_SHRUB); + case SWAMP: return new SwampTreeFeature(NoFeatureConfig::deserialize); + case ACACIA: return new SavannaTreeFeature(NoFeatureConfig::deserialize, true); + case DARK_OAK: return new DarkOakTreeFeature(NoFeatureConfig::deserialize, true); + case MEGA_REDWOOD: return new MegaPineTree(NoFeatureConfig::deserialize, true, random.nextBoolean()); + case TALL_BIRCH: return new BirchTreeFeature(NoFeatureConfig::deserialize, true, true); + case RED_MUSHROOM: return new BigRedMushroomFeature(BigMushroomFeatureConfig::deserialize); + case BROWN_MUSHROOM: return new BigBrownMushroomFeature(BigMushroomFeatureConfig::deserialize); case RANDOM: return createTreeFeatureGenerator(TreeType.values()[ThreadLocalRandom.current().nextInt(TreeType.values().length)]); - case RANDOM_REDWOOD: default: return null; } } + private IFeatureConfig createFeatureConfig(TreeType type) { + if (type == TreeType.RED_MUSHROOM || type == TreeType.BROWN_MUSHROOM) { + return new BigMushroomFeatureConfig(true); + } else { + return new NoFeatureConfig(); + } + } + @Override public boolean generateTree(TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException { - Feature generator = createTreeFeatureGenerator(type); - return generator != null && generator.place(getWorld(), getWorld().getChunkProvider().getChunkGenerator(), random, ForgeAdapter.toBlockPos(position), new NoFeatureConfig()); + @SuppressWarnings("unchecked") + Feature generator = (Feature) createTreeFeatureGenerator(type); + return generator != null + && generator.place(getWorld(), getWorld().getChunkProvider().getChunkGenerator(), random, + ForgeAdapter.toBlockPos(position), createFeatureConfig(type)); } @Override @@ -388,7 +402,7 @@ public class ForgeWorld extends AbstractWorld { public void fixLighting(Iterable chunks) { World world = getWorld(); for (BlockVector2 chunk : chunks) { - world.getChunk(chunk.getBlockX(), chunk.getBlockZ()).resetRelightChecks(); + world.getChunkProvider().getLightManager().func_215571_a(new ChunkPos(chunk.getBlockX(), chunk.getBlockZ()), true); } } @@ -447,7 +461,7 @@ public class ForgeWorld extends AbstractWorld { @Override public int getMaxY() { - return getWorld().getHeight() - 1; + return getWorld().getMaxHeight() - 1; } @Override @@ -457,11 +471,9 @@ public class ForgeWorld extends AbstractWorld { @Override public BlockState getBlock(BlockVector3 position) { - IBlockState mcState = getWorld().getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4).getBlockState( - position.getBlockX(), - position.getBlockY(), - position.getBlockZ() - ); + net.minecraft.block.BlockState mcState = getWorld() + .getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4) + .getBlockState(ForgeAdapter.toBlockPos(position)); BlockState matchingBlock = BlockStateIdAccess.getBlockStateById(Block.getStateId(mcState)); if (matchingBlock != null) { @@ -475,7 +487,7 @@ public class ForgeWorld extends AbstractWorld { public BaseBlock getFullBlock(BlockVector3 position) { BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); // Avoid creation by using the CHECK mode -- if it's needed, it'll be re-created anyways - TileEntity tile = getWorld().getChunk(pos).getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK); + TileEntity tile = getWorld().getChunk(pos).getTileEntity(pos, Chunk.CreateEntityType.CHECK); if (tile != null) { return getBlock(position).toBaseBlock(NBTConverter.fromNative(TileEntityUtils.copyNbtData(tile))); @@ -507,33 +519,34 @@ public class ForgeWorld extends AbstractWorld { @Override public List getEntities(Region region) { - List entities = new ArrayList<>(); - for (net.minecraft.entity.Entity entity : getWorld().loadedEntityList) { - if (region.contains(BlockVector3.at(entity.posX, entity.posY, entity.posZ))) { - entities.add(new ForgeEntity(entity)); - } + final World world = getWorld(); + if (!(world instanceof ServerWorld)) { + return Collections.emptyList(); } - return entities; + return ((ServerWorld) world).getEntities().filter(e -> region.contains(ForgeAdapter.adapt(e.getPosition()))) + .map(ForgeEntity::new).collect(Collectors.toList()); } @Override public List getEntities() { - List entities = new ArrayList<>(); - for (net.minecraft.entity.Entity entity : getWorld().loadedEntityList) { - entities.add(new ForgeEntity(entity)); + final World world = getWorld(); + if (!(world instanceof ServerWorld)) { + return Collections.emptyList(); } - return entities; + return ((ServerWorld) world).getEntities().map(ForgeEntity::new).collect(Collectors.toList()); } @Nullable @Override public Entity createEntity(Location location, BaseEntity entity) { World world = getWorld(); - net.minecraft.entity.Entity createdEntity = EntityType.create(world, new ResourceLocation(entity.getType().getId())); + final Optional> entityType = EntityType.getTypeFromString(entity.getType().getId()); + if (!entityType.isPresent()) return null; + net.minecraft.entity.Entity createdEntity = entityType.get().create(world); if (createdEntity != null) { CompoundTag nativeTag = entity.getNbtData(); if (nativeTag != null) { - NBTTagCompound tag = NBTConverter.toNative(entity.getNbtData()); + CompoundNBT tag = NBTConverter.toNative(entity.getNbtData()); for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { tag.remove(name); } @@ -542,7 +555,7 @@ public class ForgeWorld extends AbstractWorld { createdEntity.setLocationAndAngles(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - world.spawnEntity(createdEntity); + world.addEntity(createdEntity); return new ForgeEntity(createdEntity); } else { return null; @@ -553,10 +566,23 @@ public class ForgeWorld extends AbstractWorld { * Thrown when the reference to the world is lost. */ @SuppressWarnings("serial") - private static class WorldReferenceLostException extends WorldEditException { + private static final class WorldReferenceLostException extends WorldEditException { private WorldReferenceLostException(String message) { super(message); } } + private static class NoOpChunkStatusListener implements IChunkStatusListener { + @Override + public void func_219509_a(ChunkPos chunkPos) { + } + + @Override + public void func_219508_a(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) { + } + + @Override + public void func_219510_b() { + } + } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index a72a881a6..e7cc7d4f0 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -19,9 +19,6 @@ package com.sk89q.worldedit.forge; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; - import com.mojang.brigadier.ParseResults; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.sk89q.worldedit.LocalSession; @@ -42,12 +39,13 @@ import com.sk89q.worldedit.world.entity.EntityType; import com.sk89q.worldedit.world.item.ItemCategory; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.command.CommandSource; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.tags.BlockTags; import net.minecraft.tags.ItemTags; -import net.minecraft.util.EnumHand; +import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.CommandEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; @@ -60,9 +58,11 @@ import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.loading.FMLPaths; import net.minecraftforge.registries.ForgeRegistries; import org.apache.logging.log4j.LogManager; @@ -74,6 +74,9 @@ import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; + /** * The Forge implementation of WorldEdit. */ @@ -216,12 +219,12 @@ public class ForgeWorldEdit { event instanceof PlayerInteractEvent.RightClickBlock && ((PlayerInteractEvent.RightClickBlock) event) .getUseItem() == Event.Result.DENY; - if (isLeftDeny || isRightDeny || event.getEntity().world.isRemote || event.getHand() == EnumHand.OFF_HAND) { + if (isLeftDeny || isRightDeny || event.getEntity().world.isRemote || event.getHand() == Hand.OFF_HAND) { return; } WorldEdit we = WorldEdit.getInstance(); - ForgePlayer player = adaptPlayer((EntityPlayerMP) event.getEntityPlayer()); + ForgePlayer player = adaptPlayer((ServerPlayerEntity) event.getEntityPlayer()); ForgeWorld world = getWorld(event.getEntityPlayer().world); if (event instanceof PlayerInteractEvent.LeftClickEmpty) { @@ -256,10 +259,10 @@ public class ForgeWorldEdit { @SubscribeEvent public void onCommandEvent(CommandEvent event) throws CommandSyntaxException { ParseResults parseResults = event.getParseResults(); - if (!(parseResults.getContext().getSource().getEntity() instanceof EntityPlayerMP)) { + if (!(parseResults.getContext().getSource().getEntity() instanceof ServerPlayerEntity)) { return; } - EntityPlayerMP player = parseResults.getContext().getSource().asPlayer(); + ServerPlayerEntity player = parseResults.getContext().getSource().asPlayer(); if (player.world.isRemote()) { return; } @@ -288,7 +291,7 @@ public class ForgeWorldEdit { * @param player the player * @return the session */ - public LocalSession getSession(EntityPlayerMP player) { + public LocalSession getSession(ServerPlayerEntity player) { checkNotNull(player); return WorldEdit.getInstance().getSessionManager().get(adaptPlayer(player)); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java index bf18bd29f..9187464c2 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/KeyHandler.java @@ -22,6 +22,7 @@ package com.sk89q.worldedit.forge; import com.sk89q.worldedit.forge.gui.GuiReferenceCard; import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; +import net.minecraft.util.text.StringTextComponent; import net.minecraftforge.client.event.InputEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.registry.ClientRegistry; @@ -39,7 +40,7 @@ public class KeyHandler { @SubscribeEvent public void onKey(InputEvent.KeyInputEvent evt) { if (mc.player != null && mc.world != null && mainKey.isPressed()) { - mc.displayGuiScreen(new GuiReferenceCard()); + mc.displayGuiScreen(new GuiReferenceCard(new StringTextComponent("WorldEdit Reference"))); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java index bae43851c..7e773d7ab 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/NBTConverter.java @@ -32,19 +32,19 @@ import com.sk89q.jnbt.LongTag; import com.sk89q.jnbt.ShortTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; -import net.minecraft.nbt.INBTBase; -import net.minecraft.nbt.NBTTagByte; -import net.minecraft.nbt.NBTTagByteArray; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagDouble; -import net.minecraft.nbt.NBTTagEnd; -import net.minecraft.nbt.NBTTagFloat; -import net.minecraft.nbt.NBTTagInt; -import net.minecraft.nbt.NBTTagIntArray; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.nbt.NBTTagLong; -import net.minecraft.nbt.NBTTagShort; -import net.minecraft.nbt.NBTTagString; +import net.minecraft.nbt.ByteArrayNBT; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.DoubleNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ByteNBT; +import net.minecraft.nbt.EndNBT; +import net.minecraft.nbt.FloatNBT; +import net.minecraft.nbt.IntArrayNBT; +import net.minecraft.nbt.IntNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.LongNBT; +import net.minecraft.nbt.StringNBT; +import net.minecraft.nbt.ShortNBT; import java.util.ArrayList; import java.util.Arrays; @@ -62,7 +62,7 @@ final class NBTConverter { private NBTConverter() { } - public static INBTBase toNative(Tag tag) { + public static INBT toNative(Tag tag) { if (tag instanceof IntArrayTag) { return toNative((IntArrayTag) tag); @@ -100,13 +100,13 @@ final class NBTConverter { } } - public static NBTTagIntArray toNative(IntArrayTag tag) { + public static IntArrayNBT toNative(IntArrayTag tag) { int[] value = tag.getValue(); - return new NBTTagIntArray(Arrays.copyOf(value, value.length)); + return new IntArrayNBT(Arrays.copyOf(value, value.length)); } - public static NBTTagList toNative(ListTag tag) { - NBTTagList list = new NBTTagList(); + public static ListNBT toNative(ListTag tag) { + ListNBT list = new ListNBT(); for (Tag child : tag.getValue()) { if (child instanceof EndTag) { continue; @@ -116,94 +116,94 @@ final class NBTConverter { return list; } - public static NBTTagLong toNative(LongTag tag) { - return new NBTTagLong(tag.getValue()); + public static LongNBT toNative(LongTag tag) { + return new LongNBT(tag.getValue()); } - public static NBTTagString toNative(StringTag tag) { - return new NBTTagString(tag.getValue()); + public static StringNBT toNative(StringTag tag) { + return new StringNBT(tag.getValue()); } - public static NBTTagInt toNative(IntTag tag) { - return new NBTTagInt(tag.getValue()); + public static IntNBT toNative(IntTag tag) { + return new IntNBT(tag.getValue()); } - public static NBTTagByte toNative(ByteTag tag) { - return new NBTTagByte(tag.getValue()); + public static ByteNBT toNative(ByteTag tag) { + return new ByteNBT(tag.getValue()); } - public static NBTTagByteArray toNative(ByteArrayTag tag) { + public static ByteArrayNBT toNative(ByteArrayTag tag) { byte[] value = tag.getValue(); - return new NBTTagByteArray(Arrays.copyOf(value, value.length)); + return new ByteArrayNBT(Arrays.copyOf(value, value.length)); } - public static NBTTagCompound toNative(CompoundTag tag) { - NBTTagCompound compound = new NBTTagCompound(); + public static CompoundNBT toNative(CompoundTag tag) { + CompoundNBT compound = new CompoundNBT(); for (Entry child : tag.getValue().entrySet()) { compound.put(child.getKey(), toNative(child.getValue())); } return compound; } - public static NBTTagFloat toNative(FloatTag tag) { - return new NBTTagFloat(tag.getValue()); + public static FloatNBT toNative(FloatTag tag) { + return new FloatNBT(tag.getValue()); } - public static NBTTagShort toNative(ShortTag tag) { - return new NBTTagShort(tag.getValue()); + public static ShortNBT toNative(ShortTag tag) { + return new ShortNBT(tag.getValue()); } - public static NBTTagDouble toNative(DoubleTag tag) { - return new NBTTagDouble(tag.getValue()); + public static DoubleNBT toNative(DoubleTag tag) { + return new DoubleNBT(tag.getValue()); } - public static Tag fromNative(INBTBase other) { - if (other instanceof NBTTagIntArray) { - return fromNative((NBTTagIntArray) other); + public static Tag fromNative(INBT other) { + if (other instanceof IntArrayNBT) { + return fromNative((IntArrayNBT) other); - } else if (other instanceof NBTTagList) { - return fromNative((NBTTagList) other); + } else if (other instanceof ListNBT) { + return fromNative((ListNBT) other); - } else if (other instanceof NBTTagEnd) { - return fromNative((NBTTagEnd) other); + } else if (other instanceof EndNBT) { + return fromNative((EndNBT) other); - } else if (other instanceof NBTTagLong) { - return fromNative((NBTTagLong) other); + } else if (other instanceof LongNBT) { + return fromNative((LongNBT) other); - } else if (other instanceof NBTTagString) { - return fromNative((NBTTagString) other); + } else if (other instanceof StringNBT) { + return fromNative((StringNBT) other); - } else if (other instanceof NBTTagInt) { - return fromNative((NBTTagInt) other); + } else if (other instanceof IntNBT) { + return fromNative((IntNBT) other); - } else if (other instanceof NBTTagByte) { - return fromNative((NBTTagByte) other); + } else if (other instanceof ByteNBT) { + return fromNative((ByteNBT) other); - } else if (other instanceof NBTTagByteArray) { - return fromNative((NBTTagByteArray) other); + } else if (other instanceof ByteArrayNBT) { + return fromNative((ByteArrayNBT) other); - } else if (other instanceof NBTTagCompound) { - return fromNative((NBTTagCompound) other); + } else if (other instanceof CompoundNBT) { + return fromNative((CompoundNBT) other); - } else if (other instanceof NBTTagFloat) { - return fromNative((NBTTagFloat) other); + } else if (other instanceof FloatNBT) { + return fromNative((FloatNBT) other); - } else if (other instanceof NBTTagShort) { - return fromNative((NBTTagShort) other); + } else if (other instanceof ShortNBT) { + return fromNative((ShortNBT) other); - } else if (other instanceof NBTTagDouble) { - return fromNative((NBTTagDouble) other); + } else if (other instanceof DoubleNBT) { + return fromNative((DoubleNBT) other); } else { throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName()); } } - public static IntArrayTag fromNative(NBTTagIntArray other) { + public static IntArrayTag fromNative(IntArrayNBT other) { int[] value = other.getIntArray(); return new IntArrayTag(Arrays.copyOf(value, value.length)); } - public static ListTag fromNative(NBTTagList other) { + public static ListTag fromNative(ListNBT other) { other = other.copy(); List list = new ArrayList<>(); Class listClass = StringTag.class; @@ -216,32 +216,32 @@ final class NBTConverter { return new ListTag(listClass, list); } - public static EndTag fromNative(NBTTagEnd other) { + public static EndTag fromNative(EndNBT other) { return new EndTag(); } - public static LongTag fromNative(NBTTagLong other) { + public static LongTag fromNative(LongNBT other) { return new LongTag(other.getLong()); } - public static StringTag fromNative(NBTTagString other) { + public static StringTag fromNative(StringNBT other) { return new StringTag(other.getString()); } - public static IntTag fromNative(NBTTagInt other) { + public static IntTag fromNative(IntNBT other) { return new IntTag(other.getInt()); } - public static ByteTag fromNative(NBTTagByte other) { + public static ByteTag fromNative(ByteNBT other) { return new ByteTag(other.getByte()); } - public static ByteArrayTag fromNative(NBTTagByteArray other) { + public static ByteArrayTag fromNative(ByteArrayNBT other) { byte[] value = other.getByteArray(); return new ByteArrayTag(Arrays.copyOf(value, value.length)); } - public static CompoundTag fromNative(NBTTagCompound other) { + public static CompoundTag fromNative(CompoundNBT other) { Set tags = other.keySet(); Map map = new HashMap<>(); for (String tagName : tags) { @@ -250,15 +250,15 @@ final class NBTConverter { return new CompoundTag(map); } - public static FloatTag fromNative(NBTTagFloat other) { + public static FloatTag fromNative(FloatNBT other) { return new FloatTag(other.getFloat()); } - public static ShortTag fromNative(NBTTagShort other) { + public static ShortTag fromNative(ShortNBT other) { return new ShortTag(other.getShort()); } - public static DoubleTag fromNative(NBTTagDouble other) { + public static DoubleTag fromNative(DoubleNBT other) { return new DoubleTag(other.getDouble()); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java index 5f80516eb..0cb76b0ef 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java @@ -19,7 +19,7 @@ package com.sk89q.worldedit.forge; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; @@ -58,10 +58,10 @@ public class ThreadSafeCache { Set onlineIds = new HashSet<>(); MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - if (server == null || server.getPlayerList() == null) { + if (server == null) { return; } - for (EntityPlayerMP player : server.getPlayerList().getPlayers()) { + for (ServerPlayerEntity player : server.getPlayerList().getPlayers()) { if (player != null) { onlineIds.add(player.getUniqueID()); } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java index 41ec90f66..843d290c8 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/TileEntityUtils.java @@ -23,8 +23,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.math.BlockVector3; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagInt; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.IntNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -45,13 +45,13 @@ final class TileEntityUtils { * @param tag the tag * @param position the position */ - private static void updateForSet(NBTTagCompound tag, BlockVector3 position) { + private static void updateForSet(CompoundNBT tag, BlockVector3 position) { checkNotNull(tag); checkNotNull(position); - tag.put("x", new NBTTagInt(position.getBlockX())); - tag.put("y", new NBTTagInt(position.getBlockY())); - tag.put("z", new NBTTagInt(position.getBlockZ())); + tag.put("x", new IntNBT(position.getBlockX())); + tag.put("y", new IntNBT(position.getBlockY())); + tag.put("z", new IntNBT(position.getBlockZ())); } /** @@ -62,7 +62,7 @@ final class TileEntityUtils { * @param position the position * @param tag the tag for the tile entity (may be null to do nothing) */ - static void setTileEntity(World world, BlockVector3 position, @Nullable NBTTagCompound tag) { + static void setTileEntity(World world, BlockVector3 position, @Nullable CompoundNBT tag) { if (tag != null) { updateForSet(tag, position); TileEntity tileEntity = TileEntity.create(tag); @@ -72,8 +72,8 @@ final class TileEntityUtils { } } - public static NBTTagCompound copyNbtData(TileEntity tile) { - NBTTagCompound tag = new NBTTagCompound(); + public static CompoundNBT copyNbtData(TileEntity tile) { + CompoundNBT tag = new CompoundNBT(); tile.write(tag); return tag; } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java index 153c602f1..53897176e 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java @@ -20,21 +20,29 @@ package com.sk89q.worldedit.forge; import com.mojang.authlib.GameProfile; -import net.minecraft.world.WorldServer; +import net.minecraft.inventory.container.INamedContainerProvider; +import net.minecraft.world.ServerWorld; import net.minecraftforge.common.util.FakePlayer; +import javax.annotation.Nullable; +import java.util.OptionalInt; import java.util.UUID; public class WorldEditFakePlayer extends FakePlayer { private static final GameProfile FAKE_GAME_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); - public WorldEditFakePlayer(WorldServer world) { + public WorldEditFakePlayer(ServerWorld world) { super(world, FAKE_GAME_PROFILE); } @Override - public boolean canEat(boolean ignoreHunger) { + public boolean canEat(boolean checkHunger) { return true; } + + @Override + public OptionalInt openContainer(@Nullable INamedContainerProvider container) { + return OptionalInt.empty(); + } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java index a3b9756af..7321cdc07 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/GuiReferenceCard.java @@ -20,46 +20,46 @@ package com.sk89q.worldedit.forge.gui; import com.sk89q.worldedit.forge.ForgeWorldEdit; -import net.minecraft.client.gui.GuiButton; -import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.client.gui.screen.Screen; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import org.lwjgl.opengl.GL11; @OnlyIn(Dist.CLIENT) -public class GuiReferenceCard extends GuiScreen { +public class GuiReferenceCard extends Screen { - private GuiButton closeButton; + private Button closeButton; private int backgroundWidth = 256; private int backgroundHeight = 256; - @Override - public void initGui() { - this.closeButton = new GuiButton(0, (this.width - this.backgroundWidth + 100) / 2, - (this.height + this.backgroundHeight - 60) / 2, this.backgroundWidth - 100, 20, "Close") { - @Override - public void onClick(double mouseX, double mouseY) { - super.onClick(mouseX, mouseY); + public GuiReferenceCard(ITextComponent title) { + super(title); + } - mc.player.closeScreen(); - } - }; + @Override + public void init() { + this.addButton(closeButton = new Button( + (this.width - this.backgroundWidth + 56) / 2, (this.height + this.backgroundHeight) / 2, + 200, 20, "Close", + button -> this.minecraft.player.closeScreen())); } @Override public void render(int mouseX, int mouseY, float par3) { int x = (this.width - this.backgroundWidth) / 2; - int y = (this.height - this.backgroundHeight) / 2 - this.closeButton.height; + int y = (this.height - this.backgroundHeight) / 2 - this.closeButton.getHeight(); GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - this.mc.textureManager.bindTexture(new ResourceLocation(ForgeWorldEdit.MOD_ID, "textures/gui/reference.png")); - this.drawTexturedModalRect(x, y, 0, 0, this.backgroundWidth, this.backgroundHeight); + this.minecraft.textureManager.bindTexture(new ResourceLocation(ForgeWorldEdit.MOD_ID, "textures/gui/reference.png")); + this.blit(x, y, 0, 0, this.backgroundWidth, this.backgroundHeight); super.render(mouseX, mouseY, par3); } @Override - public boolean doesGuiPauseGame() { + public boolean isPauseScreen() { return true; } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/ResourceLocationInteractionObject.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/ResourceLocationInteractionObject.java deleted file mode 100644 index 6e11d02dd..000000000 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/gui/ResourceLocationInteractionObject.java +++ /dev/null @@ -1,65 +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 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.forge.gui; - -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.inventory.Container; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.world.IInteractionObject; - -import javax.annotation.Nullable; - -public class ResourceLocationInteractionObject implements IInteractionObject { - - private ResourceLocation resourceLocation; - - public ResourceLocationInteractionObject(ResourceLocation resourceLocation) { - this.resourceLocation = resourceLocation; - } - - @Override - public Container createContainer(InventoryPlayer inventoryPlayer, EntityPlayer entityPlayer) { - throw new UnsupportedOperationException(); - } - - @Override - public String getGuiID() { - return resourceLocation.toString(); - } - - @Override - public ITextComponent getName() { - return new TextComponentString(resourceLocation.toString()); - } - - @Override - public boolean hasCustomName() { - return false; - } - - @Nullable - @Override - public ITextComponent getCustomName() { - return null; - } -} diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java index 4295047a9..4866f4394 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/PacketHandlerUtil.java @@ -42,7 +42,7 @@ final class PacketHandlerUtil { private static Predicate validateLenient(String protocolVersion) { return remoteVersion -> protocolVersion.equals(remoteVersion) - || NetworkRegistry.ABSENT.equals(remoteVersion) - || NetworkRegistry.ACCEPTVANILLA.equals(remoteVersion); + || NetworkRegistry.ABSENT.equals(remoteVersion) + || NetworkRegistry.ACCEPTVANILLA.equals(remoteVersion); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java index d726a0eb1..2fd40fa23 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java @@ -23,9 +23,9 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.forge.ForgePlayer; import com.sk89q.worldedit.forge.ForgeWorldEdit; import net.minecraft.client.Minecraft; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.network.ThreadQuickExitException; -import net.minecraft.network.play.server.SPacketCustomPayload; +import net.minecraft.network.play.server.SCustomPayloadPlayPacket; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.network.NetworkEvent.ClientCustomPayloadEvent; import net.minecraftforge.fml.network.NetworkEvent.ServerCustomPayloadEvent; @@ -45,14 +45,13 @@ public final class WECUIPacketHandler { .buildLenientHandler(ForgeWorldEdit.CUI_PLUGIN_CHANNEL, PROTOCOL_VERSION) .eventNetworkChannel(); - public static void init() { HANDLER.addListener(WECUIPacketHandler::onPacketData); HANDLER.addListener(WECUIPacketHandler::callProcessPacket); } public static void onPacketData(ServerCustomPayloadEvent event) { - EntityPlayerMP player = event.getSource().get().getSender(); + ServerPlayerEntity player = event.getSource().get().getSender(); LocalSession session = ForgeWorldEdit.inst.getSession(player); if (session.hasCUISupport()) { @@ -67,11 +66,12 @@ public final class WECUIPacketHandler { public static void callProcessPacket(ClientCustomPayloadEvent event) { try { - new SPacketCustomPayload( + new SCustomPayloadPlayPacket( new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL), event.getPayload() ).processPacket(Minecraft.getInstance().player.connection); } catch (ThreadQuickExitException ignored) { } } + } \ No newline at end of file From dcd1d8d0bcaf2480a1041465a94397de6d6f1fa7 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 16 Jun 2019 10:09:35 -0400 Subject: [PATCH 212/366] Clean up/fix undo/redo. Add separate .self perm nodes. --- .../worldedit/command/HistoryCommands.java | 62 +++++++++++-------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index c5bb07699..afc8b1f0c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -55,33 +55,37 @@ public class HistoryCommands { aliases = { "/undo" }, desc = "Undoes the last action (from history)" ) - @CommandPermissions("worldedit.history.undo") + @CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"}) public void undo(Player player, LocalSession session, @Arg(desc = "Number of undoes to perform", def = "1") int times, @Arg(name = "player", desc = "Undo this player's operations", def = "") String playerName) throws WorldEditException { times = Math.max(1, times); - for (int i = 0; i < times; ++i) { - LocalSession undoSession = session; - if (playerName != null) { - player.checkPermission("worldedit.history.undo.other"); - LocalSession sess = worldEdit.getSessionManager().findByName(playerName); - if (sess == null) { - player.printError("Unable to find session for " + playerName); - break; - } - undoSession = session; + LocalSession undoSession = session; + if (playerName != null) { + player.checkPermission("worldedit.history.undo.other"); + undoSession = worldEdit.getSessionManager().findByName(playerName); + if (undoSession == null) { + player.printError("Unable to find session for " + playerName); + return; } + } + int timesUndone = 0; + for (int i = 0; i < times; ++i) { EditSession undone = undoSession.undo(undoSession.getBlockBag(player), player); if (undone != null) { - player.print("Undo successful."); + timesUndone++; worldEdit.flushBlockBag(player, undone); } else { - player.printError("Nothing left to undo."); break; } } + if (timesUndone > 0) { + player.print("Undid " + timesUndone + " available edits."); + } else { + player.printError("Nothing left to undo."); + } } @Command( @@ -89,33 +93,37 @@ public class HistoryCommands { aliases = { "/redo" }, desc = "Redoes the last action (from history)" ) - @CommandPermissions("worldedit.history.redo") + @CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"}) public void redo(Player player, LocalSession session, @Arg(desc = "Number of redoes to perform", def = "1") int times, @Arg(name = "player", desc = "Redo this player's operations", def = "") String playerName) throws WorldEditException { times = Math.max(1, times); - for (int i = 0; i < times; ++i) { - LocalSession redoSession = session; - if (playerName != null) { - player.checkPermission("worldedit.history.redo.other"); - LocalSession sess = worldEdit.getSessionManager().findByName(playerName); - if (sess == null) { - player.printError("Unable to find session for " + playerName); - break; - } - redoSession = session; + LocalSession redoSession = session; + if (playerName != null) { + player.checkPermission("worldedit.history.redo.other"); + redoSession = worldEdit.getSessionManager().findByName(playerName); + if (redoSession == null) { + player.printError("Unable to find session for " + playerName); + return; } + } + int timesRedone = 0; + for (int i = 0; i < times; ++i) { EditSession redone = redoSession.redo(redoSession.getBlockBag(player), player); if (redone != null) { - player.print("Redo successful."); + timesRedone++; worldEdit.flushBlockBag(player, redone); } else { - player.printError("Nothing left to redo."); break; } } + if (timesRedone > 0) { + player.print("Redid " + timesRedone + " available edits."); + } else { + player.printError("Nothing left to redo."); + } } @Command( @@ -124,7 +132,7 @@ public class HistoryCommands { desc = "Clear your history" ) @CommandPermissions("worldedit.history.clear") - public void clearHistory(Player player, LocalSession session) throws WorldEditException { + public void clearHistory(Player player, LocalSession session) { session.clearHistory(); player.print("History cleared."); } From a3d23fdcea1f199dc20368f0a021c70e02606162 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 20 Jun 2019 18:51:29 -0400 Subject: [PATCH 213/366] Fix requirements of sponge schematic spec. Fixes WORLDEDIT-3929. --- .../clipboard/io/SpongeSchematicReader.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) 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 4a9362b6e..e5d6c2e51 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 @@ -129,21 +129,28 @@ public class SpongeSchematicReader extends NBTSchematicReader { BlockVector3 origin; Region region; Map schematic = schematicTag.getValue(); - Map metadata = requireTag(schematic, "Metadata", CompoundTag.class).getValue(); int width = requireTag(schematic, "Width", ShortTag.class).getValue(); int height = requireTag(schematic, "Height", ShortTag.class).getValue(); int length = requireTag(schematic, "Length", ShortTag.class).getValue(); - int[] offsetParts = requireTag(schematic, "Offset", IntArrayTag.class).getValue(); - if (offsetParts.length != 3) { - throw new IOException("Invalid offset specified in schematic."); + IntArrayTag offsetTag = getTag(schematic, "Offset", IntArrayTag.class); + int[] offsetParts; + if (offsetTag != null) { + offsetParts = offsetTag.getValue(); + if (offsetParts.length != 3) { + throw new IOException("Invalid offset specified in schematic."); + } + } else { + offsetParts = new int[] {0, 0, 0}; } BlockVector3 min = BlockVector3.at(offsetParts[0], offsetParts[1], offsetParts[2]); - if (metadata.containsKey("WEOffsetX")) { + CompoundTag metadataTag = getTag(schematic, "Metadata", CompoundTag.class); + if (metadataTag != null && metadataTag.containsKey("WEOffsetX")) { // We appear to have WorldEdit Metadata + Map metadata = metadataTag.getValue(); int offsetX = requireTag(metadata, "WEOffsetX", IntTag.class).getValue(); int offsetY = requireTag(metadata, "WEOffsetY", IntTag.class).getValue(); int offsetZ = requireTag(metadata, "WEOffsetZ", IntTag.class).getValue(); From 902754ce8abdf092a6c45f06bfe6800c6c024547 Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 21 Jun 2019 11:07:03 -0400 Subject: [PATCH 214/366] Bit more cleanup for schematic handling. --- .../clipboard/io/SpongeSchematicReader.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) 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 e5d6c2e51..865dae6fd 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 @@ -162,9 +162,9 @@ public class SpongeSchematicReader extends NBTSchematicReader { region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE)); } - int paletteMax = requireTag(schematic, "PaletteMax", IntTag.class).getValue(); + IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class); Map paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue(); - if (paletteObject.size() != paletteMax) { + if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue()) { throw new IOException("Block palette size does not match expected size."); } @@ -206,15 +206,17 @@ public class SpongeSchematicReader extends NBTSchematicReader { for (Map tileEntity : tileEntityTags) { int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue(); final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]); + Map values = Maps.newHashMap(tileEntity); + values.put("x", new IntTag(pt.getBlockX())); + values.put("y", new IntTag(pt.getBlockY())); + values.put("z", new IntTag(pt.getBlockZ())); + values.put("id", values.get("Id")); + values.remove("Id"); + values.remove("Pos"); if (fixer != null) { - Map values = Maps.newHashMap(tileEntity); - values.put("x", new IntTag(pt.getBlockX())); - values.put("y", new IntTag(pt.getBlockY())); - values.put("z", new IntTag(pt.getBlockZ())); - values.put("id", values.get("Id")); - values.remove("Id"); - values.remove("Pos"); tileEntity = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values), dataVersion).getValue(); + } else { + tileEntity = values; } tileEntitiesMap.put(pt, tileEntity); } @@ -234,7 +236,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { while (true) { value |= (blocks[i] & 127) << (varintLength++ * 7); if (varintLength > 5) { - throw new RuntimeException("VarInt too big (probably corrupted data)"); + throw new IOException("VarInt too big (probably corrupted data)"); } if ((blocks[i] & 128) != 128) { i++; @@ -284,9 +286,8 @@ public class SpongeSchematicReader extends NBTSchematicReader { if (maxTag.getValue() != paletteTag.getValue().size()) { throw new IOException("Biome palette size does not match expected size."); } - Map paletteEntries = paletteTag.getValue(); - for (Entry palettePart : paletteEntries.entrySet()) { + for (Entry palettePart : paletteTag.getValue().entrySet()) { String key = palettePart.getKey(); if (fixer != null) { key = fixer.fixUp(DataFixer.FixTypes.BIOME, key, dataVersion); @@ -318,7 +319,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { while (true) { bVal |= (biomes[biomeJ] & 127) << (varIntLength++ * 7); if (varIntLength > 5) { - throw new RuntimeException("VarInt too big (probably corrupted data)"); + throw new IOException("VarInt too big (probably corrupted data)"); } if (((biomes[biomeJ] & 128) != 128)) { biomeJ++; From d763ab374caa102b15c07681bdb3f43277f825e8 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 22 Jun 2019 14:20:14 -0400 Subject: [PATCH 215/366] Re-add delchunks command (#481) The new command now writes a json file to WorldEdit's working directory with instructions on which chunks to delete, which is read by the plugin/mod at startup and calls the ChunkDeleter. The chunk deleter parses the json and iterates the instructions, backing up .mca files as it goes and overwriting the offset headers with 0 wherever a chunk needs to be deleted. This allows Minecraft to reclaim the space used for that chunk, as well as forcing it to be generated from scratch next time the area is loaded. --- .../sk89q/worldedit/bukkit/BukkitWorld.java | 6 + .../worldedit/bukkit/WorldEditPlugin.java | 10 + .../bukkit/adapter/BukkitImplLoader.java | 3 - .../worldedit/command/ChunkCommands.java | 170 ++++----- .../internal/anvil/ChunkDeleter.java | 350 ++++++++++++++++++ .../internal/anvil/ChunkDeletionInfo.java | 48 +++ .../internal/anvil/RegionAccess.java | 101 +++++ .../sk89q/worldedit/world/AbstractWorld.java | 6 + .../java/com/sk89q/worldedit/world/World.java | 12 + .../world/storage/McRegionReader.java | 9 +- .../com/sk89q/worldedit/forge/ForgeWorld.java | 10 + .../sk89q/worldedit/forge/ForgeWorldEdit.java | 14 +- .../sk89q/worldedit/sponge/SpongeWorld.java | 6 + .../worldedit/sponge/SpongeWorldEdit.java | 9 + 14 files changed, 650 insertions(+), 104 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java 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 1613f46eb..977985df7 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 @@ -53,6 +53,7 @@ import org.slf4j.Logger; import javax.annotation.Nullable; import java.lang.ref.WeakReference; +import java.nio.file.Path; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; @@ -158,6 +159,11 @@ public class BukkitWorld extends AbstractWorld { return getWorld().getName(); } + @Override + public Path getStoragePath() { + return getWorld().getWorldFolder().toPath(); + } + @Override public int getBlockLightLevel(BlockVector3 pt) { return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel(); 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 4ac9a3ee1..a81aab7c5 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 @@ -38,6 +38,7 @@ import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.internal.command.CommandUtil; +import com.sk89q.worldedit.internal.anvil.ChunkDeleter; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockCategory; @@ -73,6 +74,9 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; import java.util.Locale; import java.util.Map; @@ -82,6 +86,7 @@ import java.util.logging.Level; import java.util.zip.ZipEntry; import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; /** * Plugin for Bukkit. @@ -109,6 +114,11 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // Setup platform server = new BukkitServerInterface(this, getServer()); worldEdit.getPlatformManager().register(server); + + Path delChunks = Paths.get(getDataFolder().getPath(), DELCHUNKS_FILE_NAME); + if (Files.exists(delChunks)) { + ChunkDeleter.runFromFile(delChunks, true); + } } /** diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java index 950e4f862..5d464181f 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java @@ -156,9 +156,6 @@ public class BukkitImplLoader { if (cls.isSynthetic()) continue; if (BukkitImplAdapter.class.isAssignableFrom(cls)) { return (BukkitImplAdapter) cls.newInstance(); - } else { - log.debug("Failed to load the Bukkit adapter class '" + className + - "' because it does not implement " + BukkitImplAdapter.class.getCanonicalName()); } } catch (ClassNotFoundException e) { log.warn("Failed to load the Bukkit adapter class '" + className + diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index af1e4e95d..450547740 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -19,10 +19,7 @@ package com.sk89q.worldedit.command; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; - -import com.sk89q.worldedit.LocalConfiguration; +import com.google.gson.JsonIOException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -30,22 +27,36 @@ import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.internal.anvil.ChunkDeleter; +import com.sk89q.worldedit.internal.anvil.ChunkDeletionInfo; import com.sk89q.worldedit.math.BlockVector2; -import com.sk89q.worldedit.math.MathUtils; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.storage.LegacyChunkStore; import com.sk89q.worldedit.world.storage.McRegionChunkStore; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.ArgFlag; +import org.enginehub.piston.exception.StopExecutionException; -import java.io.FileOutputStream; +import java.io.File; import java.io.IOException; -import java.io.OutputStreamWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.Set; import java.util.stream.Collectors; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; +import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; + /** * Commands for working with chunks. */ @@ -69,15 +80,10 @@ public class ChunkCommands { int chunkX = (int) Math.floor(pos.getBlockX() / 16.0); int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0); - String folder1 = Integer.toString(MathUtils.divisorMod(chunkX, 64), 36); - String folder2 = Integer.toString(MathUtils.divisorMod(chunkZ, 64), 36); - String filename = "c." + Integer.toString(chunkX, 36) - + "." + Integer.toString(chunkZ, 36) + ".dat"; - + final BlockVector2 chunkPos = BlockVector2.at(chunkX, chunkZ); player.print("Chunk: " + chunkX + ", " + chunkZ); - player.print("Old format: " + folder1 + "/" + folder2 + "/" + filename); - player.print("McRegion: region/" + McRegionChunkStore.getFilename( - BlockVector2.at(chunkX, chunkZ))); + player.print("Old format: " + LegacyChunkStore.getFilename(chunkPos)); + player.print("McRegion: region/" + McRegionChunkStore.getFilename(chunkPos)); } @Command( @@ -86,7 +92,7 @@ public class ChunkCommands { ) @CommandPermissions("worldedit.listchunks") public void listChunks(Player player, LocalSession session, - @ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException { + @ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException { Set chunks = session.getSelection(player.getWorld()).getChunks(); PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks -p %page%", @@ -100,82 +106,64 @@ public class ChunkCommands { ) @CommandPermissions("worldedit.delchunks") @Logging(REGION) - public void deleteChunks(Player player, LocalSession session) throws WorldEditException { - player.print("Note that this command does not yet support the mcregion format."); - LocalConfiguration config = worldEdit.getConfiguration(); - - Set chunks = session.getSelection(player.getWorld()).getChunks(); - FileOutputStream out = null; - - if (config.shellSaveType == null) { - player.printError("Shell script type must be configured: 'bat' or 'bash' expected."); - } else if (config.shellSaveType.equalsIgnoreCase("bat")) { - try { - out = new FileOutputStream("worldedit-delchunks.bat"); - OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); - writer.write("@ECHO off\r\n"); - writer.write("ECHO This batch file was generated by WorldEdit.\r\n"); - writer.write("ECHO It contains a list of chunks that were in the selected region\r\n"); - writer.write("ECHO at the time that the /delchunks command was used. Run this file\r\n"); - writer.write("ECHO in order to delete the chunk files listed in this file.\r\n"); - writer.write("ECHO.\r\n"); - writer.write("PAUSE\r\n"); - - for (BlockVector2 chunk : chunks) { - String filename = LegacyChunkStore.getFilename(chunk); - writer.write("ECHO " + filename + "\r\n"); - writer.write("DEL \"world/" + filename + "\"\r\n"); - } - - writer.write("ECHO Complete.\r\n"); - writer.write("PAUSE\r\n"); - writer.close(); - player.print("worldedit-delchunks.bat written. Run it when no one is near the region."); - } catch (IOException e) { - player.printError("Error occurred: " + e.getMessage()); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException ignored) { } - } - } - } else if (config.shellSaveType.equalsIgnoreCase("bash")) { - try { - out = new FileOutputStream("worldedit-delchunks.sh"); - OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); - writer.write("#!/bin/bash\n"); - writer.write("echo This shell file was generated by WorldEdit.\n"); - writer.write("echo It contains a list of chunks that were in the selected region\n"); - writer.write("echo at the time that the /delchunks command was used. Run this file\n"); - writer.write("echo in order to delete the chunk files listed in this file.\n"); - writer.write("echo\n"); - writer.write("read -p \"Press any key to continue...\"\n"); - - for (BlockVector2 chunk : chunks) { - String filename = LegacyChunkStore.getFilename(chunk); - writer.write("echo " + filename + "\n"); - writer.write("rm \"world/" + filename + "\"\n"); - } - - writer.write("echo Complete.\n"); - writer.write("read -p \"Press any key to continue...\"\n"); - writer.close(); - player.print("worldedit-delchunks.sh written. Run it when no one is near the region."); - player.print("You will have to chmod it to be executable."); - } catch (IOException e) { - player.printError("Error occurred: " + e.getMessage()); - } finally { - if (out != null) { - try { - out.close(); - } catch (IOException ignored) { - } - } - } - } else { - player.printError("Shell script type must be configured: 'bat' or 'bash' expected."); + public void deleteChunks(Player player, LocalSession session, + @ArgFlag(name = 'o', desc = "Only delete chunks older than the specified time.", def = "") + ZonedDateTime beforeTime) throws WorldEditException { + Path worldDir = player.getWorld().getStoragePath(); + if (worldDir == null) { + throw new StopExecutionException(TextComponent.of("Couldn't find world folder for this world.")); } + + File chunkFile = worldEdit.getWorkingDirectoryFile(DELCHUNKS_FILE_NAME); + Path chunkPath = chunkFile.toPath(); + ChunkDeletionInfo currentInfo = null; + if (Files.exists(chunkPath)) { + try { + currentInfo = ChunkDeleter.readInfo(chunkFile.toPath()); + } catch (IOException e) { + throw new StopExecutionException(TextComponent.of("Error reading existing chunk file.")); + } + } + if (currentInfo == null) { + currentInfo = new ChunkDeletionInfo(); + currentInfo.batches = new ArrayList<>(); + } + + ChunkDeletionInfo.ChunkBatch newBatch = new ChunkDeletionInfo.ChunkBatch(); + newBatch.worldPath = worldDir.toAbsolutePath().normalize().toString(); + newBatch.backup = true; + final Region selection = session.getSelection(player.getWorld()); + int chunkCount; + if (selection instanceof CuboidRegion) { + newBatch.minChunk = BlockVector2.at(selection.getMinimumPoint().getBlockX() >> 4, selection.getMinimumPoint().getBlockZ() >> 4); + newBatch.maxChunk = BlockVector2.at(selection.getMaximumPoint().getBlockX() >> 4, selection.getMaximumPoint().getBlockZ() >> 4); + final BlockVector2 dist = newBatch.maxChunk.subtract(newBatch.minChunk).add(1, 1); + chunkCount = dist.getBlockX() * dist.getBlockZ(); + } else { + // this has a possibility to OOM for very large selections still + Set chunks = selection.getChunks(); + newBatch.chunks = new ArrayList<>(chunks); + chunkCount = chunks.size(); + } + if (beforeTime != null) { + newBatch.deletionPredicates = new ArrayList<>(); + ChunkDeletionInfo.DeletionPredicate timePred = new ChunkDeletionInfo.DeletionPredicate(); + timePred.property = "modification"; + timePred.comparison = "<"; + timePred.value = String.valueOf((int) beforeTime.toOffsetDateTime().toEpochSecond()); + newBatch.deletionPredicates.add(timePred); + } + currentInfo.batches.add(newBatch); + + try { + ChunkDeleter.writeInfo(currentInfo, chunkPath); + } catch (IOException | JsonIOException e) { + throw new StopExecutionException(TextComponent.of("Failed to write chunk list: " + e.getMessage())); + } + + player.print(String.format("%d chunk(s) have been marked for deletion and will be deleted the next time the server starts.", chunkCount)); + player.print(TextComponent.of("You can mark more chunks for deletion, or to stop the server now, run: ", TextColor.LIGHT_PURPLE) + .append(TextComponent.of("/stop", TextColor.AQUA).clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop")))); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java new file mode 100644 index 000000000..71106c3b3 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java @@ -0,0 +1,350 @@ +/* + * 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.internal.anvil; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonIOException; +import com.google.gson.JsonSyntaxException; +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.sk89q.worldedit.math.BlockVector2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.BiPredicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class ChunkDeleter { + + public static final String DELCHUNKS_FILE_NAME = "delete_chunks.json"; + private static final Logger logger = LoggerFactory.getLogger(ChunkDeleter.class); + + private static final Comparator chunkSorter = Comparator.comparing( + pos -> (pos.getBlockX() & 31) + (pos.getBlockZ() & 31) * 32); + + private static Gson chunkDeleterGson = new GsonBuilder() + .registerTypeAdapter(BlockVector2.class, new BlockVector2Adapter()) + .setPrettyPrinting() + .create(); + + public static ChunkDeletionInfo readInfo(Path chunkFile) throws IOException, JsonSyntaxException { + String json = new String(Files.readAllBytes(chunkFile), StandardCharsets.UTF_8); + return chunkDeleterGson.fromJson(json, ChunkDeletionInfo.class); + } + + public static void writeInfo(ChunkDeletionInfo info, Path chunkFile) throws IOException, JsonIOException { + String json = chunkDeleterGson.toJson(info, new TypeToken() {}.getType()); + try (BufferedWriter writer = Files.newBufferedWriter(chunkFile, StandardOpenOption.CREATE)) { + writer.write(json); + } + } + + public static void runFromFile(Path chunkFile, boolean deleteOnSuccess) { + ChunkDeleter chunkDeleter; + try { + chunkDeleter = createFromFile(chunkFile); + } catch (JsonSyntaxException | IOException e) { + logger.error("Could not parse chunk deletion file. Invalid file?", e); + return; + } + logger.info("Found chunk deletions. Proceeding with deletion..."); + long start = System.currentTimeMillis(); + if (chunkDeleter.runDeleter()) { + logger.info("Successfully deleted {} matching chunks (out of {}, taking {} ms).", + chunkDeleter.getDeletedChunkCount(), chunkDeleter.getDeletionsRequested(), + System.currentTimeMillis() - start); + if (deleteOnSuccess) { + boolean deletedFile = false; + try { + deletedFile = Files.deleteIfExists(chunkFile); + } catch (IOException ignored) { + } + if (!deletedFile) { + logger.warn("Chunk deletion file could not be cleaned up. This may have unintended consequences" + + " on next startup, or if /delchunks is used again."); + } + } + } else { + logger.error("Error occurred while deleting chunks. " + + "If world errors occur, stop the server and restore the *.bak backup files."); + } + } + + private ChunkDeleter(ChunkDeletionInfo chunkDeletionInfo) { + this.chunkDeletionInfo = chunkDeletionInfo; + } + + private static ChunkDeleter createFromFile(Path chunkFile) throws IOException { + ChunkDeletionInfo info = readInfo(chunkFile); + if (info == null) { + throw new IOException("Read null json. Empty file?"); + } + return new ChunkDeleter(info); + } + + private final ChunkDeletionInfo chunkDeletionInfo; + private Set backedUpRegions = new HashSet<>(); + private boolean shouldPreload; + private int debugRate = 100; + private int totalChunksDeleted = 0; + private int deletionsRequested = 0; + + private boolean runDeleter() { + return chunkDeletionInfo.batches.stream().allMatch(this::runBatch); + } + + private boolean runBatch(ChunkDeletionInfo.ChunkBatch chunkBatch) { + logger.debug("Processing deletion batch."); + final Map> regionToChunkList = groupChunks(chunkBatch); + BiPredicate predicate = createPredicates(chunkBatch.deletionPredicates); + shouldPreload = chunkBatch.chunks == null; + return regionToChunkList.entrySet().stream().allMatch(entry -> { + Path regionPath = entry.getKey(); + if (!Files.exists(regionPath)) return true; + if (chunkBatch.backup && !backedUpRegions.contains(regionPath)) { + try { + backupRegion(regionPath); + } catch (IOException e) { + logger.warn("Error backing up region file: " + regionPath + ". Aborting the process.", e); + return false; + } + } + return deleteChunks(regionPath, entry.getValue(), predicate); + }); + } + + private Map> groupChunks(ChunkDeletionInfo.ChunkBatch chunkBatch) { + Path worldPath = Paths.get(chunkBatch.worldPath); + if (chunkBatch.chunks != null) { + deletionsRequested += chunkBatch.chunks.size(); + debugRate = chunkBatch.chunks.size() / 10; + return chunkBatch.chunks.stream() + .collect(Collectors.groupingBy(RegionFilePos::new)) + .entrySet().stream().collect(Collectors.toMap( + e -> worldPath.resolve("region").resolve(e.getKey().getFileName()), + e -> e.getValue().stream().sorted(chunkSorter))); + } else { + final BlockVector2 minChunk = chunkBatch.minChunk; + final BlockVector2 maxChunk = chunkBatch.maxChunk; + final RegionFilePos minRegion = new RegionFilePos(minChunk); + final RegionFilePos maxRegion = new RegionFilePos(maxChunk); + Map> groupedChunks = new HashMap<>(); + for (int regX = minRegion.getX(); regX <= maxRegion.getX(); regX++) { + for (int regZ = minRegion.getZ(); regZ <= maxRegion.getZ(); regZ++) { + final Path regionPath = worldPath.resolve("region").resolve(new RegionFilePos(regX, regZ).getFileName()); + if (!Files.exists(regionPath)) continue; + int startX = regX << 5; + int endX = (regX << 5) + 31; + int startZ = regZ << 5; + int endZ = (regZ << 5) + 31; + + int minX = Math.max(Math.min(startX, endX), minChunk.getBlockX()); + int minZ = Math.max(Math.min(startZ, endZ), minChunk.getBlockZ()); + int maxX = Math.min(Math.max(startX, endX), maxChunk.getBlockX()); + int maxZ = Math.min(Math.max(startZ, endZ), maxChunk.getBlockZ()); + Stream stream = Stream.iterate(BlockVector2.at(minX, minZ), + bv2 -> { + int nextX = bv2.getBlockX(); + int nextZ = bv2.getBlockZ(); + if (++nextX > maxX) { + nextX = minX; + if (++nextZ > maxZ) { + return null; + } + } + return BlockVector2.at(nextX, nextZ); + }); + groupedChunks.put(regionPath, stream); + } + } + final BlockVector2 dist = maxChunk.subtract(minChunk).add(1, 1); + final int batchSize = dist.getBlockX() * dist.getBlockZ(); + debugRate = batchSize / 10; + this.deletionsRequested += batchSize; + return groupedChunks; + } + } + + private BiPredicate createPredicates(List deletionPredicates) { + if (deletionPredicates == null) return (r, p) -> true; + return deletionPredicates.stream() + .map(this::createPredicate) + .reduce(BiPredicate::and) + .orElse((r, p) -> true); + } + + private BiPredicate createPredicate(ChunkDeletionInfo.DeletionPredicate deletionPredicate) { + if ("modification".equals(deletionPredicate.property)) { + int time; + try { + time = Integer.parseInt(deletionPredicate.value); + } catch (NumberFormatException e) { + throw new IllegalStateException("Modification time predicate specified invalid time: " + deletionPredicate.value); + } + switch (deletionPredicate.comparison) { + case "<": + return (r, p) -> { + try { + return r.getModificationTime(p) < time; + } catch (IOException e) { + return false; + } + }; + case ">": + return (r, p) -> { + try { + return r.getModificationTime(p) > time; + } catch (IOException e) { + return false; + } + }; + default: + throw new IllegalStateException("Unexpected comparison value: " + deletionPredicate.comparison); + } + } + throw new IllegalStateException("Unexpected property value: " + deletionPredicate.property); + } + + private void backupRegion(Path regionFile) throws IOException { + Path backupFile = regionFile.resolveSibling(regionFile.getFileName() + ".bak"); + Files.copy(regionFile, backupFile, StandardCopyOption.REPLACE_EXISTING); + backedUpRegions.add(backupFile); + } + + private boolean deleteChunks(Path regionFile, Stream chunks, + BiPredicate deletionPredicate) { + try (RegionAccess region = new RegionAccess(regionFile, shouldPreload)) { + for (Iterator iterator = chunks.iterator(); iterator.hasNext();) { + BlockVector2 chunk = iterator.next(); + if (chunk == null) break; + if (deletionPredicate.test(region, chunk)) { + region.deleteChunk(chunk); + totalChunksDeleted++; + if (totalChunksDeleted % debugRate == 0) { + logger.debug("Deleted {} chunks so far.", totalChunksDeleted); + } + } else { + logger.debug("Chunk did not match predicates: " + chunk); + } + } + return true; + } catch (IOException e) { + logger.warn("Error deleting chunks from region: " + regionFile + ". Aborting the process.", e); + return false; + } + } + + public int getDeletedChunkCount() { + return totalChunksDeleted; + } + + public int getDeletionsRequested() { + return deletionsRequested; + } + + private static class BlockVector2Adapter extends TypeAdapter { + @Override + public void write(JsonWriter out, BlockVector2 value) throws IOException { + out.beginArray(); + out.value(value.getBlockX()); + out.value(value.getBlockZ()); + out.endArray(); + } + + @Override + public BlockVector2 read(JsonReader in) throws IOException { + in.beginArray(); + int x = in.nextInt(); + int z = in.nextInt(); + in.endArray(); + return BlockVector2.at(x, z); + } + } + + private static class RegionFilePos { + private final int x; + private final int z; + + RegionFilePos(BlockVector2 chunk) { + this.x = chunk.getBlockX() >> 5; + this.z = chunk.getBlockZ() >> 5; + } + + RegionFilePos(int regX, int regZ) { + this.x = regX; + this.z = regZ; + } + + public int getX() { + return x; + } + + public int getZ() { + return z; + } + + public String getFileName() { + return "r." + x + "." + z + ".mca"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RegionFilePos that = (RegionFilePos) o; + + if (x != that.x) return false; + return z == that.z; + + } + + @Override + public int hashCode() { + int result = x; + result = 31 * result + z; + return result; + } + + @Override + public String toString() { + return "(" + x + ", " + z + ")"; + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java new file mode 100644 index 000000000..7e03ba502 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java @@ -0,0 +1,48 @@ +/* + * 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.internal.anvil; + +import com.sk89q.worldedit.math.BlockVector2; + +import java.util.List; + +/** + * Internal class. Subject to changes. + */ +public class ChunkDeletionInfo { + + public List batches; + + public static class ChunkBatch { + public String worldPath; + public boolean backup; + public List deletionPredicates; + // specify either list of chunks, or min-max + public List chunks; + public BlockVector2 minChunk; + public BlockVector2 maxChunk; + } + + public static class DeletionPredicate { + public String property; + public String comparison; + public String value; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java new file mode 100644 index 000000000..9446773a6 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/RegionAccess.java @@ -0,0 +1,101 @@ +/* + * 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.internal.anvil; + +import com.sk89q.worldedit.math.BlockVector2; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.file.Path; + +/** + * Internal class. Subject to changes. + */ +class RegionAccess implements AutoCloseable { + + private RandomAccessFile raf; + private int[] offsets; + private int[] timestamps; + + RegionAccess(Path file) throws IOException { + this(file, false); + } + + RegionAccess(Path file, boolean preload) throws IOException { + raf = new RandomAccessFile(file.toFile(), "rw"); + if (preload) { + readHeaders(); + } + } + + private void readHeaders() throws IOException { + offsets = new int[1024]; + timestamps = new int[1024]; + for (int idx = 0; idx < 1024; ++idx) { + offsets[idx] = raf.readInt(); + } + for (int idx = 0; idx < 1024; ++idx) { + timestamps[idx] = raf.readInt(); + } + } + + private static int indexChunk(BlockVector2 pos) { + int x = pos.getBlockX() & 31; + int z = pos.getBlockZ() & 31; + return x + z * 32; + } + + int getModificationTime(BlockVector2 pos) throws IOException { + int idx = indexChunk(pos); + if (timestamps != null) { + return timestamps[idx]; + } + raf.seek(idx * 4L + 4096); + return raf.readInt(); + } + + int getChunkSize(BlockVector2 pos) throws IOException { + int idx = indexChunk(pos); + if (offsets != null) { + return offsets[idx] & 0xFF; + } + raf.seek(idx * 4L); + // 3 bytes for offset + raf.read(); + raf.read(); + raf.read(); + // one byte for size - note, yes, could do raf.readInt() & 0xFF but that does extra checks + return raf.read(); + } + + void deleteChunk(BlockVector2 pos) throws IOException { + int idx = indexChunk(pos); + raf.seek(idx * 4L); + raf.writeInt(0); + if (offsets != null) { + offsets[idx] = 0; + } + } + + @Override + public void close() throws IOException { + raf.close(); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index 5fb92af03..201cac554 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import java.nio.file.Path; import java.util.PriorityQueue; import javax.annotation.Nullable; @@ -56,6 +57,11 @@ public abstract class AbstractWorld implements World { return setBlock(pt, block, true); } + @Override + public Path getStoragePath() { + return null; + } + @Override public int getMaxY() { return getMaximumPoint().getBlockY(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index cad0be0f5..471279281 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -38,6 +38,9 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.weather.WeatherType; +import javax.annotation.Nullable; +import java.nio.file.Path; + /** * Represents a world (dimension). */ @@ -50,6 +53,15 @@ public interface World extends Extent { */ String getName(); + /** + * Get the folder in which this world is stored. May return null if unknown + * or if this world is not serialized to disk. + * + * @return world storage path + */ + @Nullable + Path getStoragePath(); + /** * Get the maximum Y. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java index e991216ae..29f37df31 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/storage/McRegionReader.java @@ -100,10 +100,9 @@ public class McRegionReader { /** * Read the header. * - * @throws DataException * @throws IOException */ - private void readHeader() throws DataException, IOException { + private void readHeader() throws IOException { offsets = new int[SECTOR_INTS]; for (int i = 0; i < SECTOR_INTS; ++i) { @@ -124,10 +123,6 @@ public class McRegionReader { int x = position.getBlockX() & 31; int z = position.getBlockZ() & 31; - if (x < 0 || x >= 32 || z < 0 || z >= 32) { - throw new DataException("MCRegion file does not contain " + x + "," + z); - } - int offset = getOffset(x, z); // The chunk hasn't been generated @@ -138,7 +133,7 @@ public class McRegionReader { int sectorNumber = offset >> 8; int numSectors = offset & 0xFF; - stream.seek(sectorNumber * SECTOR_BYTES); + stream.seek((long) sectorNumber * SECTOR_BYTES); int length = dataStream.readInt(); if (length > SECTOR_BYTES * numSectors) { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 3c2d374b4..0e2c50ad7 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -97,6 +97,7 @@ import net.minecraft.world.storage.WorldInfo; import javax.annotation.Nullable; import java.io.File; import java.lang.ref.WeakReference; +import java.nio.file.Path; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -167,6 +168,15 @@ public class ForgeWorld extends AbstractWorld { return getWorld().getWorldInfo().getWorldName(); } + @Override + public Path getStoragePath() { + final World world = getWorld(); + if (world instanceof ServerWorld) { + return ((ServerWorld) world).getSaveHandler().getWorldDirectory().toPath(); + } + return null; + } + @Override public > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { checkNotNull(position); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index e7cc7d4f0..a3ad1c9a0 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.forge.net.packet.LeftClickAirEventMessage; import com.sk89q.worldedit.forge.proxy.ClientProxy; import com.sk89q.worldedit.forge.proxy.CommonProxy; import com.sk89q.worldedit.forge.proxy.ServerProxy; +import com.sk89q.worldedit.internal.anvil.ChunkDeleter; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockCategory; @@ -45,7 +46,6 @@ import net.minecraft.tags.ItemTags; import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; -import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.CommandEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; @@ -58,11 +58,10 @@ import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; +import net.minecraftforge.fml.event.server.FMLServerAboutToStartEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.loading.FMLPaths; import net.minecraftforge.registries.ForgeRegistries; import org.apache.logging.log4j.LogManager; @@ -76,6 +75,7 @@ import java.nio.file.Path; import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.forge.ForgeAdapter.adaptPlayer; +import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; /** * The Forge implementation of WorldEdit. @@ -180,6 +180,14 @@ public class ForgeWorldEdit { } } + @SubscribeEvent + public void serverAboutToStart(FMLServerAboutToStartEvent event) { + final Path delChunks = workingDir.resolve(DELCHUNKS_FILE_NAME); + if (Files.exists(delChunks)) { + ChunkDeleter.runFromFile(delChunks, true); + } + } + @SubscribeEvent public void serverStopping(FMLServerStoppingEvent event) { WorldEdit worldEdit = WorldEdit.getInstance(); diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java index 743bf7198..04b1961ff 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java @@ -57,6 +57,7 @@ import org.spongepowered.api.world.World; import org.spongepowered.api.world.weather.Weather; import java.lang.ref.WeakReference; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -116,6 +117,11 @@ public abstract class SpongeWorld extends AbstractWorld { return getWorld().getName(); } + @Override + public Path getStoragePath() { + return getWorld().getDirectory(); + } + @SuppressWarnings("WeakerAccess") protected BlockState getBlockState(BlockStateHolder block) { if (block instanceof com.sk89q.worldedit.world.block.BlockState) { diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java index d875d4938..711648a3c 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.sponge; import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; import com.google.inject.Inject; import com.sk89q.worldedit.LocalSession; @@ -29,6 +30,7 @@ import com.sk89q.worldedit.event.platform.PlatformReadyEvent; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.internal.anvil.ChunkDeleter; import com.sk89q.worldedit.sponge.adapter.AdapterLoadException; import com.sk89q.worldedit.sponge.adapter.SpongeImplAdapter; import com.sk89q.worldedit.sponge.adapter.SpongeImplLoader; @@ -62,6 +64,8 @@ import org.spongepowered.api.world.World; import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -134,6 +138,11 @@ public class SpongeWorldEdit { WorldEdit.getInstance().getPlatformManager().unregister(platform); } + final Path delChunks = workingDir.toPath().resolve(DELCHUNKS_FILE_NAME); + if (Files.exists(delChunks)) { + ChunkDeleter.runFromFile(delChunks, true); + } + this.platform = new SpongePlatform(this); this.provider = new SpongePermissionsProvider(); From 8fcc22c21d58397c2ae6dcd9ade2c10238cb9c76 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 22 Jun 2019 14:59:46 -0400 Subject: [PATCH 216/366] Cleanup multiple batch usage for chunk deletion. --- .../sk89q/worldedit/command/ChunkCommands.java | 16 +++++++++------- .../worldedit/internal/anvil/ChunkDeleter.java | 16 +++++++--------- .../internal/anvil/ChunkDeletionInfo.java | 6 ++++++ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index 450547740..e9a9e231d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -133,17 +133,13 @@ public class ChunkCommands { newBatch.worldPath = worldDir.toAbsolutePath().normalize().toString(); newBatch.backup = true; final Region selection = session.getSelection(player.getWorld()); - int chunkCount; if (selection instanceof CuboidRegion) { newBatch.minChunk = BlockVector2.at(selection.getMinimumPoint().getBlockX() >> 4, selection.getMinimumPoint().getBlockZ() >> 4); newBatch.maxChunk = BlockVector2.at(selection.getMaximumPoint().getBlockX() >> 4, selection.getMaximumPoint().getBlockZ() >> 4); - final BlockVector2 dist = newBatch.maxChunk.subtract(newBatch.minChunk).add(1, 1); - chunkCount = dist.getBlockX() * dist.getBlockZ(); } else { // this has a possibility to OOM for very large selections still Set chunks = selection.getChunks(); newBatch.chunks = new ArrayList<>(chunks); - chunkCount = chunks.size(); } if (beforeTime != null) { newBatch.deletionPredicates = new ArrayList<>(); @@ -161,9 +157,15 @@ public class ChunkCommands { throw new StopExecutionException(TextComponent.of("Failed to write chunk list: " + e.getMessage())); } - player.print(String.format("%d chunk(s) have been marked for deletion and will be deleted the next time the server starts.", chunkCount)); - player.print(TextComponent.of("You can mark more chunks for deletion, or to stop the server now, run: ", TextColor.LIGHT_PURPLE) - .append(TextComponent.of("/stop", TextColor.AQUA).clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop")))); + player.print(String.format("%d chunk(s) have been marked for deletion the next time the server starts.", + newBatch.getChunkCount())); + if (currentInfo.batches.size() > 1) { + player.printDebug(String.format("%d chunks total marked for deletion. (May have overlaps).", + currentInfo.batches.stream().mapToInt(ChunkDeletionInfo.ChunkBatch::getChunkCount).sum())); + } + player.print(TextComponent.of("You can mark more chunks for deletion, or to stop now, run: ", TextColor.LIGHT_PURPLE) + .append(TextComponent.of("/stop", TextColor.AQUA) + .clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop")))); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java index 71106c3b3..665210694 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeleter.java @@ -70,7 +70,7 @@ public final class ChunkDeleter { public static void writeInfo(ChunkDeletionInfo info, Path chunkFile) throws IOException, JsonIOException { String json = chunkDeleterGson.toJson(info, new TypeToken() {}.getType()); - try (BufferedWriter writer = Files.newBufferedWriter(chunkFile, StandardOpenOption.CREATE)) { + try (BufferedWriter writer = Files.newBufferedWriter(chunkFile)) { writer.write(json); } } @@ -130,10 +130,14 @@ public final class ChunkDeleter { } private boolean runBatch(ChunkDeletionInfo.ChunkBatch chunkBatch) { - logger.debug("Processing deletion batch."); + int chunkCount = chunkBatch.getChunkCount(); + logger.debug("Processing deletion batch with {} chunks.", chunkCount); final Map> regionToChunkList = groupChunks(chunkBatch); BiPredicate predicate = createPredicates(chunkBatch.deletionPredicates); shouldPreload = chunkBatch.chunks == null; + deletionsRequested += chunkCount; + debugRate = chunkCount / 10; + return regionToChunkList.entrySet().stream().allMatch(entry -> { Path regionPath = entry.getKey(); if (!Files.exists(regionPath)) return true; @@ -152,8 +156,6 @@ public final class ChunkDeleter { private Map> groupChunks(ChunkDeletionInfo.ChunkBatch chunkBatch) { Path worldPath = Paths.get(chunkBatch.worldPath); if (chunkBatch.chunks != null) { - deletionsRequested += chunkBatch.chunks.size(); - debugRate = chunkBatch.chunks.size() / 10; return chunkBatch.chunks.stream() .collect(Collectors.groupingBy(RegionFilePos::new)) .entrySet().stream().collect(Collectors.toMap( @@ -193,10 +195,6 @@ public final class ChunkDeleter { groupedChunks.put(regionPath, stream); } } - final BlockVector2 dist = maxChunk.subtract(minChunk).add(1, 1); - final int batchSize = dist.getBlockX() * dist.getBlockZ(); - debugRate = batchSize / 10; - this.deletionsRequested += batchSize; return groupedChunks; } } @@ -256,7 +254,7 @@ public final class ChunkDeleter { if (deletionPredicate.test(region, chunk)) { region.deleteChunk(chunk); totalChunksDeleted++; - if (totalChunksDeleted % debugRate == 0) { + if (debugRate != 0 && totalChunksDeleted % debugRate == 0) { logger.debug("Deleted {} chunks so far.", totalChunksDeleted); } } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java index 7e03ba502..fcb34ccdc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/anvil/ChunkDeletionInfo.java @@ -38,6 +38,12 @@ public class ChunkDeletionInfo { public List chunks; public BlockVector2 minChunk; public BlockVector2 maxChunk; + + public int getChunkCount() { + if (chunks != null) return chunks.size(); + final BlockVector2 dist = maxChunk.subtract(minChunk).add(1, 1); + return dist.getBlockX() * dist.getBlockZ(); + } } public static class DeletionPredicate { From 7879be157eeb1dfa17ad4ca17e0c9812abbd52f4 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 22 Jun 2019 12:42:20 -0700 Subject: [PATCH 217/366] [Forge] Update to newer 1.14.2 forge, mappings --- worldedit-forge/build.gradle | 4 ++-- .../src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index ab0e28fd2..7696d677a 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -15,7 +15,7 @@ apply plugin: 'eclipse' apply plugin: 'net.minecraftforge.gradle' def minecraftVersion = "1.14.2" -def forgeVersion = "26.0.25" +def forgeVersion = "26.0.48" configurations.all { Configuration it -> it.resolutionStrategy { ResolutionStrategy rs -> @@ -36,7 +36,7 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 minecraft { - mappings channel: 'snapshot', version: "20190614-${minecraftVersion}" + mappings channel: 'snapshot', version: "20190621-${minecraftVersion}" runs { client = { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 0e2c50ad7..840680e1a 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -496,8 +496,7 @@ public class ForgeWorld extends AbstractWorld { @Override public BaseBlock getFullBlock(BlockVector3 position) { BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); - // Avoid creation by using the CHECK mode -- if it's needed, it'll be re-created anyways - TileEntity tile = getWorld().getChunk(pos).getTileEntity(pos, Chunk.CreateEntityType.CHECK); + TileEntity tile = getWorld().getChunk(pos).getTileEntity(pos); if (tile != null) { return getBlock(position).toBaseBlock(NBTConverter.fromNative(TileEntityUtils.copyNbtData(tile))); @@ -550,7 +549,7 @@ public class ForgeWorld extends AbstractWorld { @Override public Entity createEntity(Location location, BaseEntity entity) { World world = getWorld(); - final Optional> entityType = EntityType.getTypeFromString(entity.getType().getId()); + final Optional> entityType = EntityType.byKey(entity.getType().getId()); if (!entityType.isPresent()) return null; net.minecraft.entity.Entity createdEntity = entityType.get().create(world); if (createdEntity != null) { From 2347fdff62c34af40859fb2ed1d59710e01987dc Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 24 Jun 2019 22:44:12 -0400 Subject: [PATCH 218/366] [Forge] Use IClearable to clear containers. --- .../java/com/sk89q/worldedit/forge/ForgeWorld.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 840680e1a..6abda18d1 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -54,7 +54,7 @@ import net.minecraft.block.Blocks; import net.minecraft.block.LeavesBlock; import net.minecraft.entity.EntityType; import net.minecraft.entity.item.ItemEntity; -import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.IClearable; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; import net.minecraft.nbt.CompoundNBT; @@ -234,12 +234,8 @@ public class ForgeWorld extends AbstractWorld { public boolean clearContainerBlockContents(BlockVector3 position) { checkNotNull(position); TileEntity tile = getWorld().getTileEntity(ForgeAdapter.toBlockPos(position)); - if ((tile instanceof IInventory)) { - IInventory inv = (IInventory) tile; - int size = inv.getSizeInventory(); - for (int i = 0; i < size; i++) { - inv.setInventorySlotContents(i, ItemStack.EMPTY); - } + if (tile instanceof IClearable) { + ((IClearable) tile).clear(); return true; } return false; From 79910c57d78e27ae945910af13b9ac1d40fbf8ce Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 24 Jun 2019 23:15:07 -0400 Subject: [PATCH 219/366] Add 1.14 blocks, items, entities, and tags. (#490) Should remain backwards compatible with 1.13. Removed blocks/items will be forwarded to the "replacement" block/item. (e.g. BlockTypes.SIGN will find OAK_SIGN on 1.14.) --- .../factory/parser/DefaultBlockParser.java | 8 +- .../extent/reorder/MultiStageReorder.java | 3 + .../worldedit/world/biome/BiomeTypes.java | 4 +- .../world/block/BlockCategories.java | 20 +- .../worldedit/world/block/BlockTypes.java | 85 +- .../worldedit/world/entity/EntityTypes.java | 7 + .../worldedit/world/item/ItemCategories.java | 13 +- .../sk89q/worldedit/world/item/ItemTypes.java | 100 +- .../world/registry/BundledBlockData.java | 14 +- .../world/registry/BundledItemData.java | 14 +- .../worldedit/world/registry/blocks.114.json | 16902 ++++++++++++++++ .../worldedit/world/registry/items.114.json | 6141 ++++++ 12 files changed, 23295 insertions(+), 16 deletions(-) create mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.114.json create mode 100644 worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.114.json 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 55a9089b0..32736265c 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 @@ -41,6 +41,7 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockCategories; import com.sk89q.worldedit.world.block.BlockCategory; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; @@ -346,9 +347,12 @@ public class DefaultBlockParser extends InputParser { } } - final BlockCategory signCategory = BlockCategory.REGISTRY.get("minecraft:signs"); + if (!context.isTryingLegacy()) { + return state.toBaseBlock(); + } + if (blockType == BlockTypes.SIGN || blockType == BlockTypes.WALL_SIGN - || signCategory != null && signCategory.contains(blockType)) { + || BlockCategories.SIGNS.contains(blockType)) { // Allow special sign text syntax String[] text = new String[4]; text[0] = blockAndExtraData.length > 1 ? blockAndExtraData[1] : ""; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java index 3e1a7d4fa..55ddbcb73 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java @@ -61,6 +61,8 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder BlockCategories.WOODEN_PRESSURE_PLATES.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); BlockCategories.CARPETS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); BlockCategories.RAILS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + BlockCategories.BEDS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); + BlockCategories.SMALL_FLOWERS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.LAST)); priorityMap.put(BlockTypes.BLACK_BED, PlacementPriority.LAST); priorityMap.put(BlockTypes.BLUE_BED, PlacementPriority.LAST); priorityMap.put(BlockTypes.BROWN_BED, PlacementPriority.LAST); @@ -128,6 +130,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder // Final BlockCategories.DOORS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.FINAL)); BlockCategories.BANNERS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.FINAL)); + BlockCategories.SIGNS.getAll().forEach(type -> priorityMap.put(type, PlacementPriority.FINAL)); priorityMap.put(BlockTypes.SIGN, PlacementPriority.FINAL); priorityMap.put(BlockTypes.WALL_SIGN, PlacementPriority.FINAL); priorityMap.put(BlockTypes.CACTUS, PlacementPriority.FINAL); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java index a9d07a5fc..f12228e2d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeTypes.java @@ -24,10 +24,12 @@ import javax.annotation.Nullable; /** * Stores a list of common Biome String IDs. */ -public class BiomeTypes { +public final class BiomeTypes { @Nullable public static final BiomeType BADLANDS = get("minecraft:badlands"); @Nullable public static final BiomeType BADLANDS_PLATEAU = get("minecraft:badlands_plateau"); + @Nullable public static final BiomeType BAMBOO_JUNGLE = get("minecraft:bamboo_jungle"); + @Nullable public static final BiomeType BAMBOO_JUNGLE_HILLS = get("minecraft:bamboo_jungle_hills"); @Nullable public static final BiomeType BEACH = get("minecraft:beach"); @Nullable public static final BiomeType BIRCH_FOREST = get("minecraft:birch_forest"); @Nullable public static final BiomeType BIRCH_FOREST_HILLS = get("minecraft:birch_forest_hills"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java index 28c3385d5..f85fcca37 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockCategories.java @@ -26,17 +26,24 @@ public final class BlockCategories { public static final BlockCategory ACACIA_LOGS = get("minecraft:acacia_logs"); public static final BlockCategory ANVIL = get("minecraft:anvil"); + public static final BlockCategory BAMBOO_PLANTABLE_ON = get("minecraft:bamboo_plantable_on"); public static final BlockCategory BANNERS = get("minecraft:banners"); + public static final BlockCategory BEDS = get("minecraft:beds"); public static final BlockCategory BIRCH_LOGS = get("minecraft:birch_logs"); public static final BlockCategory BUTTONS = get("minecraft:buttons"); public static final BlockCategory CARPETS = get("minecraft:carpets"); - public static final BlockCategory CORALS = get("minecraft:corals"); public static final BlockCategory CORAL_BLOCKS = get("minecraft:coral_blocks"); + public static final BlockCategory CORAL_PLANTS = get("minecraft:coral_plants"); + public static final BlockCategory CORALS = get("minecraft:corals"); public static final BlockCategory DARK_OAK_LOGS = get("minecraft:dark_oak_logs"); + public static final BlockCategory DIRT_LIKE = get("minecraft:dirt_like"); public static final BlockCategory DOORS = get("minecraft:doors"); + public static final BlockCategory DRAGON_IMMUNE = get("minecraft:dragon_immune"); public static final BlockCategory ENDERMAN_HOLDABLE = get("minecraft:enderman_holdable"); + public static final BlockCategory FENCES = get("minecraft:fences"); public static final BlockCategory FLOWER_POTS = get("minecraft:flower_pots"); public static final BlockCategory ICE = get("minecraft:ice"); + public static final BlockCategory IMPERMEABLE = get("minecraft:impermeable"); public static final BlockCategory JUNGLE_LOGS = get("minecraft:jungle_logs"); public static final BlockCategory LEAVES = get("minecraft:leaves"); public static final BlockCategory LOGS = get("minecraft:logs"); @@ -45,16 +52,27 @@ public final class BlockCategories { public static final BlockCategory RAILS = get("minecraft:rails"); public static final BlockCategory SAND = get("minecraft:sand"); public static final BlockCategory SAPLINGS = get("minecraft:saplings"); + public static final BlockCategory SIGNS = get("minecraft:signs"); public static final BlockCategory SLABS = get("minecraft:slabs"); + public static final BlockCategory SMALL_FLOWERS = get("minecraft:small_flowers"); public static final BlockCategory SPRUCE_LOGS = get("minecraft:spruce_logs"); public static final BlockCategory STAIRS = get("minecraft:stairs"); + public static final BlockCategory STANDING_SIGNS = get("minecraft:standing_signs"); public static final BlockCategory STONE_BRICKS = get("minecraft:stone_bricks"); + public static final BlockCategory TRAPDOORS = get("minecraft:trapdoors"); + public static final BlockCategory UNDERWATER_BONEMEALS = get("minecraft:underwater_bonemeals"); public static final BlockCategory VALID_SPAWN = get("minecraft:valid_spawn"); + public static final BlockCategory WALL_CORALS = get("minecraft:wall_corals"); + public static final BlockCategory WALL_SIGNS = get("minecraft:wall_signs"); + public static final BlockCategory WALLS = get("minecraft:walls"); + public static final BlockCategory WITHER_IMMUNE = get("minecraft:wither_immune"); public static final BlockCategory WOODEN_BUTTONS = get("minecraft:wooden_buttons"); public static final BlockCategory WOODEN_DOORS = get("minecraft:wooden_doors"); + public static final BlockCategory WOODEN_FENCES = get("minecraft:wooden_fences"); public static final BlockCategory WOODEN_PRESSURE_PLATES = get("minecraft:wooden_pressure_plates"); public static final BlockCategory WOODEN_SLABS = get("minecraft:wooden_slabs"); public static final BlockCategory WOODEN_STAIRS = get("minecraft:wooden_stairs"); + public static final BlockCategory WOODEN_TRAPDOORS = get("minecraft:wooden_trapdoors"); public static final BlockCategory WOOL = get("minecraft:wool"); private BlockCategories() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java index 1b8b44bcc..dd989ba91 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.world.block; import javax.annotation.Nullable; +import java.util.Optional; /** * Stores a list of common Block String IDs. @@ -35,22 +36,31 @@ public final class BlockTypes { @Nullable public static final BlockType ACACIA_PLANKS = get("minecraft:acacia_planks"); @Nullable public static final BlockType ACACIA_PRESSURE_PLATE = get("minecraft:acacia_pressure_plate"); @Nullable public static final BlockType ACACIA_SAPLING = get("minecraft:acacia_sapling"); + @Nullable public static final BlockType ACACIA_SIGN = get("minecraft:acacia_sign"); @Nullable public static final BlockType ACACIA_SLAB = get("minecraft:acacia_slab"); @Nullable public static final BlockType ACACIA_STAIRS = get("minecraft:acacia_stairs"); @Nullable public static final BlockType ACACIA_TRAPDOOR = get("minecraft:acacia_trapdoor"); + @Nullable public static final BlockType ACACIA_WALL_SIGN = get("minecraft:acacia_wall_sign"); @Nullable public static final BlockType ACACIA_WOOD = get("minecraft:acacia_wood"); @Nullable public static final BlockType ACTIVATOR_RAIL = get("minecraft:activator_rail"); @Nullable public static final BlockType AIR = get("minecraft:air"); @Nullable public static final BlockType ALLIUM = get("minecraft:allium"); @Nullable public static final BlockType ANDESITE = get("minecraft:andesite"); + @Nullable public static final BlockType ANDESITE_SLAB = get("minecraft:andesite_slab"); + @Nullable public static final BlockType ANDESITE_STAIRS = get("minecraft:andesite_stairs"); + @Nullable public static final BlockType ANDESITE_WALL = get("minecraft:andesite_wall"); @Nullable public static final BlockType ANVIL = get("minecraft:anvil"); @Nullable public static final BlockType ATTACHED_MELON_STEM = get("minecraft:attached_melon_stem"); @Nullable public static final BlockType ATTACHED_PUMPKIN_STEM = get("minecraft:attached_pumpkin_stem"); @Nullable public static final BlockType AZURE_BLUET = get("minecraft:azure_bluet"); + @Nullable public static final BlockType BAMBOO = get("minecraft:bamboo"); + @Nullable public static final BlockType BAMBOO_SAPLING = get("minecraft:bamboo_sapling"); + @Nullable public static final BlockType BARREL = get("minecraft:barrel"); @Nullable public static final BlockType BARRIER = get("minecraft:barrier"); @Nullable public static final BlockType BEACON = get("minecraft:beacon"); @Nullable public static final BlockType BEDROCK = get("minecraft:bedrock"); @Nullable public static final BlockType BEETROOTS = get("minecraft:beetroots"); + @Nullable public static final BlockType BELL = get("minecraft:bell"); @Nullable public static final BlockType BIRCH_BUTTON = get("minecraft:birch_button"); @Nullable public static final BlockType BIRCH_DOOR = get("minecraft:birch_door"); @Nullable public static final BlockType BIRCH_FENCE = get("minecraft:birch_fence"); @@ -60,9 +70,11 @@ public final class BlockTypes { @Nullable public static final BlockType BIRCH_PLANKS = get("minecraft:birch_planks"); @Nullable public static final BlockType BIRCH_PRESSURE_PLATE = get("minecraft:birch_pressure_plate"); @Nullable public static final BlockType BIRCH_SAPLING = get("minecraft:birch_sapling"); + @Nullable public static final BlockType BIRCH_SIGN = get("minecraft:birch_sign"); @Nullable public static final BlockType BIRCH_SLAB = get("minecraft:birch_slab"); @Nullable public static final BlockType BIRCH_STAIRS = get("minecraft:birch_stairs"); @Nullable public static final BlockType BIRCH_TRAPDOOR = get("minecraft:birch_trapdoor"); + @Nullable public static final BlockType BIRCH_WALL_SIGN = get("minecraft:birch_wall_sign"); @Nullable public static final BlockType BIRCH_WOOD = get("minecraft:birch_wood"); @Nullable public static final BlockType BLACK_BANNER = get("minecraft:black_banner"); @Nullable public static final BlockType BLACK_BED = get("minecraft:black_bed"); @@ -76,6 +88,7 @@ public final class BlockTypes { @Nullable public static final BlockType BLACK_TERRACOTTA = get("minecraft:black_terracotta"); @Nullable public static final BlockType BLACK_WALL_BANNER = get("minecraft:black_wall_banner"); @Nullable public static final BlockType BLACK_WOOL = get("minecraft:black_wool"); + @Nullable public static final BlockType BLAST_FURNACE = get("minecraft:blast_furnace"); @Nullable public static final BlockType BLUE_BANNER = get("minecraft:blue_banner"); @Nullable public static final BlockType BLUE_BED = get("minecraft:blue_bed"); @Nullable public static final BlockType BLUE_CARPET = get("minecraft:blue_carpet"); @@ -99,6 +112,7 @@ public final class BlockTypes { @Nullable public static final BlockType BREWING_STAND = get("minecraft:brewing_stand"); @Nullable public static final BlockType BRICK_SLAB = get("minecraft:brick_slab"); @Nullable public static final BlockType BRICK_STAIRS = get("minecraft:brick_stairs"); + @Nullable public static final BlockType BRICK_WALL = get("minecraft:brick_wall"); @Nullable public static final BlockType BRICKS = get("minecraft:bricks"); @Nullable public static final BlockType BROWN_BANNER = get("minecraft:brown_banner"); @Nullable public static final BlockType BROWN_BED = get("minecraft:brown_bed"); @@ -121,7 +135,9 @@ public final class BlockTypes { @Nullable public static final BlockType BUBBLE_CORAL_WALL_FAN = get("minecraft:bubble_coral_wall_fan"); @Nullable public static final BlockType CACTUS = get("minecraft:cactus"); @Nullable public static final BlockType CAKE = get("minecraft:cake"); + @Nullable public static final BlockType CAMPFIRE = get("minecraft:campfire"); @Nullable public static final BlockType CARROTS = get("minecraft:carrots"); + @Nullable public static final BlockType CARTOGRAPHY_TABLE = get("minecraft:cartography_table"); @Nullable public static final BlockType CARVED_PUMPKIN = get("minecraft:carved_pumpkin"); @Nullable public static final BlockType CAULDRON = get("minecraft:cauldron"); @Nullable public static final BlockType CAVE_AIR = get("minecraft:cave_air"); @@ -146,13 +162,17 @@ public final class BlockTypes { @Nullable public static final BlockType COCOA = get("minecraft:cocoa"); @Nullable public static final BlockType COMMAND_BLOCK = get("minecraft:command_block"); @Nullable public static final BlockType COMPARATOR = get("minecraft:comparator"); + @Nullable public static final BlockType COMPOSTER = get("minecraft:composter"); @Nullable public static final BlockType CONDUIT = get("minecraft:conduit"); + @Nullable public static final BlockType CORNFLOWER = get("minecraft:cornflower"); @Nullable public static final BlockType CRACKED_STONE_BRICKS = get("minecraft:cracked_stone_bricks"); @Nullable public static final BlockType CRAFTING_TABLE = get("minecraft:crafting_table"); @Nullable public static final BlockType CREEPER_HEAD = get("minecraft:creeper_head"); @Nullable public static final BlockType CREEPER_WALL_HEAD = get("minecraft:creeper_wall_head"); @Nullable public static final BlockType CUT_RED_SANDSTONE = get("minecraft:cut_red_sandstone"); + @Nullable public static final BlockType CUT_RED_SANDSTONE_SLAB = get("minecraft:cut_red_sandstone_slab"); @Nullable public static final BlockType CUT_SANDSTONE = get("minecraft:cut_sandstone"); + @Nullable public static final BlockType CUT_SANDSTONE_SLAB = get("minecraft:cut_sandstone_slab"); @Nullable public static final BlockType CYAN_BANNER = get("minecraft:cyan_banner"); @Nullable public static final BlockType CYAN_BED = get("minecraft:cyan_bed"); @Nullable public static final BlockType CYAN_CARPET = get("minecraft:cyan_carpet"); @@ -176,9 +196,11 @@ public final class BlockTypes { @Nullable public static final BlockType DARK_OAK_PLANKS = get("minecraft:dark_oak_planks"); @Nullable public static final BlockType DARK_OAK_PRESSURE_PLATE = get("minecraft:dark_oak_pressure_plate"); @Nullable public static final BlockType DARK_OAK_SAPLING = get("minecraft:dark_oak_sapling"); + @Nullable public static final BlockType DARK_OAK_SIGN = get("minecraft:dark_oak_sign"); @Nullable public static final BlockType DARK_OAK_SLAB = get("minecraft:dark_oak_slab"); @Nullable public static final BlockType DARK_OAK_STAIRS = get("minecraft:dark_oak_stairs"); @Nullable public static final BlockType DARK_OAK_TRAPDOOR = get("minecraft:dark_oak_trapdoor"); + @Nullable public static final BlockType DARK_OAK_WALL_SIGN = get("minecraft:dark_oak_wall_sign"); @Nullable public static final BlockType DARK_OAK_WOOD = get("minecraft:dark_oak_wood"); @Nullable public static final BlockType DARK_PRISMARINE = get("minecraft:dark_prismarine"); @Nullable public static final BlockType DARK_PRISMARINE_SLAB = get("minecraft:dark_prismarine_slab"); @@ -209,6 +231,9 @@ public final class BlockTypes { @Nullable public static final BlockType DIAMOND_BLOCK = get("minecraft:diamond_block"); @Nullable public static final BlockType DIAMOND_ORE = get("minecraft:diamond_ore"); @Nullable public static final BlockType DIORITE = get("minecraft:diorite"); + @Nullable public static final BlockType DIORITE_SLAB = get("minecraft:diorite_slab"); + @Nullable public static final BlockType DIORITE_STAIRS = get("minecraft:diorite_stairs"); + @Nullable public static final BlockType DIORITE_WALL = get("minecraft:diorite_wall"); @Nullable public static final BlockType DIRT = get("minecraft:dirt"); @Nullable public static final BlockType DISPENSER = get("minecraft:dispenser"); @Nullable public static final BlockType DRAGON_EGG = get("minecraft:dragon_egg"); @@ -224,6 +249,9 @@ public final class BlockTypes { @Nullable public static final BlockType END_PORTAL_FRAME = get("minecraft:end_portal_frame"); @Nullable public static final BlockType END_ROD = get("minecraft:end_rod"); @Nullable public static final BlockType END_STONE = get("minecraft:end_stone"); + @Nullable public static final BlockType END_STONE_BRICK_SLAB = get("minecraft:end_stone_brick_slab"); + @Nullable public static final BlockType END_STONE_BRICK_STAIRS = get("minecraft:end_stone_brick_stairs"); + @Nullable public static final BlockType END_STONE_BRICK_WALL = get("minecraft:end_stone_brick_wall"); @Nullable public static final BlockType END_STONE_BRICKS = get("minecraft:end_stone_bricks"); @Nullable public static final BlockType ENDER_CHEST = get("minecraft:ender_chest"); @Nullable public static final BlockType FARMLAND = get("minecraft:farmland"); @@ -233,6 +261,7 @@ public final class BlockTypes { @Nullable public static final BlockType FIRE_CORAL_BLOCK = get("minecraft:fire_coral_block"); @Nullable public static final BlockType FIRE_CORAL_FAN = get("minecraft:fire_coral_fan"); @Nullable public static final BlockType FIRE_CORAL_WALL_FAN = get("minecraft:fire_coral_wall_fan"); + @Nullable public static final BlockType FLETCHING_TABLE = get("minecraft:fletching_table"); @Nullable public static final BlockType FLOWER_POT = get("minecraft:flower_pot"); @Nullable public static final BlockType FROSTED_ICE = get("minecraft:frosted_ice"); @Nullable public static final BlockType FURNACE = get("minecraft:furnace"); @@ -242,6 +271,9 @@ public final class BlockTypes { @Nullable public static final BlockType GOLD_BLOCK = get("minecraft:gold_block"); @Nullable public static final BlockType GOLD_ORE = get("minecraft:gold_ore"); @Nullable public static final BlockType GRANITE = get("minecraft:granite"); + @Nullable public static final BlockType GRANITE_SLAB = get("minecraft:granite_slab"); + @Nullable public static final BlockType GRANITE_STAIRS = get("minecraft:granite_stairs"); + @Nullable public static final BlockType GRANITE_WALL = get("minecraft:granite_wall"); @Nullable public static final BlockType GRASS = get("minecraft:grass"); @Nullable public static final BlockType GRASS_BLOCK = get("minecraft:grass_block"); @Nullable public static final BlockType GRASS_PATH = get("minecraft:grass_path"); @@ -270,6 +302,7 @@ public final class BlockTypes { @Nullable public static final BlockType GREEN_TERRACOTTA = get("minecraft:green_terracotta"); @Nullable public static final BlockType GREEN_WALL_BANNER = get("minecraft:green_wall_banner"); @Nullable public static final BlockType GREEN_WOOL = get("minecraft:green_wool"); + @Nullable public static final BlockType GRINDSTONE = get("minecraft:grindstone"); @Nullable public static final BlockType HAY_BLOCK = get("minecraft:hay_block"); @Nullable public static final BlockType HEAVY_WEIGHTED_PRESSURE_PLATE = get("minecraft:heavy_weighted_pressure_plate"); @Nullable public static final BlockType HOPPER = get("minecraft:hopper"); @@ -290,6 +323,7 @@ public final class BlockTypes { @Nullable public static final BlockType IRON_ORE = get("minecraft:iron_ore"); @Nullable public static final BlockType IRON_TRAPDOOR = get("minecraft:iron_trapdoor"); @Nullable public static final BlockType JACK_O_LANTERN = get("minecraft:jack_o_lantern"); + @Nullable public static final BlockType JIGSAW = get("minecraft:jigsaw"); @Nullable public static final BlockType JUKEBOX = get("minecraft:jukebox"); @Nullable public static final BlockType JUNGLE_BUTTON = get("minecraft:jungle_button"); @Nullable public static final BlockType JUNGLE_DOOR = get("minecraft:jungle_door"); @@ -300,17 +334,21 @@ public final class BlockTypes { @Nullable public static final BlockType JUNGLE_PLANKS = get("minecraft:jungle_planks"); @Nullable public static final BlockType JUNGLE_PRESSURE_PLATE = get("minecraft:jungle_pressure_plate"); @Nullable public static final BlockType JUNGLE_SAPLING = get("minecraft:jungle_sapling"); + @Nullable public static final BlockType JUNGLE_SIGN = get("minecraft:jungle_sign"); @Nullable public static final BlockType JUNGLE_SLAB = get("minecraft:jungle_slab"); @Nullable public static final BlockType JUNGLE_STAIRS = get("minecraft:jungle_stairs"); @Nullable public static final BlockType JUNGLE_TRAPDOOR = get("minecraft:jungle_trapdoor"); + @Nullable public static final BlockType JUNGLE_WALL_SIGN = get("minecraft:jungle_wall_sign"); @Nullable public static final BlockType JUNGLE_WOOD = get("minecraft:jungle_wood"); @Nullable public static final BlockType KELP = get("minecraft:kelp"); @Nullable public static final BlockType KELP_PLANT = get("minecraft:kelp_plant"); @Nullable public static final BlockType LADDER = get("minecraft:ladder"); + @Nullable public static final BlockType LANTERN = get("minecraft:lantern"); @Nullable public static final BlockType LAPIS_BLOCK = get("minecraft:lapis_block"); @Nullable public static final BlockType LAPIS_ORE = get("minecraft:lapis_ore"); @Nullable public static final BlockType LARGE_FERN = get("minecraft:large_fern"); @Nullable public static final BlockType LAVA = get("minecraft:lava"); + @Nullable public static final BlockType LECTERN = get("minecraft:lectern"); @Nullable public static final BlockType LEVER = get("minecraft:lever"); @Nullable public static final BlockType LIGHT_BLUE_BANNER = get("minecraft:light_blue_banner"); @Nullable public static final BlockType LIGHT_BLUE_BED = get("minecraft:light_blue_bed"); @@ -338,6 +376,7 @@ public final class BlockTypes { @Nullable public static final BlockType LIGHT_GRAY_WOOL = get("minecraft:light_gray_wool"); @Nullable public static final BlockType LIGHT_WEIGHTED_PRESSURE_PLATE = get("minecraft:light_weighted_pressure_plate"); @Nullable public static final BlockType LILAC = get("minecraft:lilac"); + @Nullable public static final BlockType LILY_OF_THE_VALLEY = get("minecraft:lily_of_the_valley"); @Nullable public static final BlockType LILY_PAD = get("minecraft:lily_pad"); @Nullable public static final BlockType LIME_BANNER = get("minecraft:lime_banner"); @Nullable public static final BlockType LIME_BED = get("minecraft:lime_bed"); @@ -351,6 +390,7 @@ public final class BlockTypes { @Nullable public static final BlockType LIME_TERRACOTTA = get("minecraft:lime_terracotta"); @Nullable public static final BlockType LIME_WALL_BANNER = get("minecraft:lime_wall_banner"); @Nullable public static final BlockType LIME_WOOL = get("minecraft:lime_wool"); + @Nullable public static final BlockType LOOM = get("minecraft:loom"); @Nullable public static final BlockType MAGENTA_BANNER = get("minecraft:magenta_banner"); @Nullable public static final BlockType MAGENTA_BED = get("minecraft:magenta_bed"); @Nullable public static final BlockType MAGENTA_CARPET = get("minecraft:magenta_carpet"); @@ -367,7 +407,12 @@ public final class BlockTypes { @Nullable public static final BlockType MELON = get("minecraft:melon"); @Nullable public static final BlockType MELON_STEM = get("minecraft:melon_stem"); @Nullable public static final BlockType MOSSY_COBBLESTONE = get("minecraft:mossy_cobblestone"); + @Nullable public static final BlockType MOSSY_COBBLESTONE_SLAB = get("minecraft:mossy_cobblestone_slab"); + @Nullable public static final BlockType MOSSY_COBBLESTONE_STAIRS = get("minecraft:mossy_cobblestone_stairs"); @Nullable public static final BlockType MOSSY_COBBLESTONE_WALL = get("minecraft:mossy_cobblestone_wall"); + @Nullable public static final BlockType MOSSY_STONE_BRICK_SLAB = get("minecraft:mossy_stone_brick_slab"); + @Nullable public static final BlockType MOSSY_STONE_BRICK_STAIRS = get("minecraft:mossy_stone_brick_stairs"); + @Nullable public static final BlockType MOSSY_STONE_BRICK_WALL = get("minecraft:mossy_stone_brick_wall"); @Nullable public static final BlockType MOSSY_STONE_BRICKS = get("minecraft:mossy_stone_bricks"); @Nullable public static final BlockType MOVING_PISTON = get("minecraft:moving_piston"); @Nullable public static final BlockType MUSHROOM_STEM = get("minecraft:mushroom_stem"); @@ -375,6 +420,7 @@ public final class BlockTypes { @Nullable public static final BlockType NETHER_BRICK_FENCE = get("minecraft:nether_brick_fence"); @Nullable public static final BlockType NETHER_BRICK_SLAB = get("minecraft:nether_brick_slab"); @Nullable public static final BlockType NETHER_BRICK_STAIRS = get("minecraft:nether_brick_stairs"); + @Nullable public static final BlockType NETHER_BRICK_WALL = get("minecraft:nether_brick_wall"); @Nullable public static final BlockType NETHER_BRICKS = get("minecraft:nether_bricks"); @Nullable public static final BlockType NETHER_PORTAL = get("minecraft:nether_portal"); @Nullable public static final BlockType NETHER_QUARTZ_ORE = get("minecraft:nether_quartz_ore"); @@ -391,9 +437,11 @@ public final class BlockTypes { @Nullable public static final BlockType OAK_PLANKS = get("minecraft:oak_planks"); @Nullable public static final BlockType OAK_PRESSURE_PLATE = get("minecraft:oak_pressure_plate"); @Nullable public static final BlockType OAK_SAPLING = get("minecraft:oak_sapling"); + @Nullable public static final BlockType OAK_SIGN = get("minecraft:oak_sign"); @Nullable public static final BlockType OAK_SLAB = get("minecraft:oak_slab"); @Nullable public static final BlockType OAK_STAIRS = get("minecraft:oak_stairs"); @Nullable public static final BlockType OAK_TRAPDOOR = get("minecraft:oak_trapdoor"); + @Nullable public static final BlockType OAK_WALL_SIGN = get("minecraft:oak_wall_sign"); @Nullable public static final BlockType OAK_WOOD = get("minecraft:oak_wood"); @Nullable public static final BlockType OBSERVER = get("minecraft:observer"); @Nullable public static final BlockType OBSIDIAN = get("minecraft:obsidian"); @@ -433,22 +481,31 @@ public final class BlockTypes { @Nullable public static final BlockType PLAYER_WALL_HEAD = get("minecraft:player_wall_head"); @Nullable public static final BlockType PODZOL = get("minecraft:podzol"); @Nullable public static final BlockType POLISHED_ANDESITE = get("minecraft:polished_andesite"); + @Nullable public static final BlockType POLISHED_ANDESITE_SLAB = get("minecraft:polished_andesite_slab"); + @Nullable public static final BlockType POLISHED_ANDESITE_STAIRS = get("minecraft:polished_andesite_stairs"); @Nullable public static final BlockType POLISHED_DIORITE = get("minecraft:polished_diorite"); + @Nullable public static final BlockType POLISHED_DIORITE_SLAB = get("minecraft:polished_diorite_slab"); + @Nullable public static final BlockType POLISHED_DIORITE_STAIRS = get("minecraft:polished_diorite_stairs"); @Nullable public static final BlockType POLISHED_GRANITE = get("minecraft:polished_granite"); + @Nullable public static final BlockType POLISHED_GRANITE_SLAB = get("minecraft:polished_granite_slab"); + @Nullable public static final BlockType POLISHED_GRANITE_STAIRS = get("minecraft:polished_granite_stairs"); @Nullable public static final BlockType POPPY = get("minecraft:poppy"); @Nullable public static final BlockType POTATOES = get("minecraft:potatoes"); @Nullable public static final BlockType POTTED_ACACIA_SAPLING = get("minecraft:potted_acacia_sapling"); @Nullable public static final BlockType POTTED_ALLIUM = get("minecraft:potted_allium"); @Nullable public static final BlockType POTTED_AZURE_BLUET = get("minecraft:potted_azure_bluet"); + @Nullable public static final BlockType POTTED_BAMBOO = get("minecraft:potted_bamboo"); @Nullable public static final BlockType POTTED_BIRCH_SAPLING = get("minecraft:potted_birch_sapling"); @Nullable public static final BlockType POTTED_BLUE_ORCHID = get("minecraft:potted_blue_orchid"); @Nullable public static final BlockType POTTED_BROWN_MUSHROOM = get("minecraft:potted_brown_mushroom"); @Nullable public static final BlockType POTTED_CACTUS = get("minecraft:potted_cactus"); + @Nullable public static final BlockType POTTED_CORNFLOWER = get("minecraft:potted_cornflower"); @Nullable public static final BlockType POTTED_DANDELION = get("minecraft:potted_dandelion"); @Nullable public static final BlockType POTTED_DARK_OAK_SAPLING = get("minecraft:potted_dark_oak_sapling"); @Nullable public static final BlockType POTTED_DEAD_BUSH = get("minecraft:potted_dead_bush"); @Nullable public static final BlockType POTTED_FERN = get("minecraft:potted_fern"); @Nullable public static final BlockType POTTED_JUNGLE_SAPLING = get("minecraft:potted_jungle_sapling"); + @Nullable public static final BlockType POTTED_LILY_OF_THE_VALLEY = get("minecraft:potted_lily_of_the_valley"); @Nullable public static final BlockType POTTED_OAK_SAPLING = get("minecraft:potted_oak_sapling"); @Nullable public static final BlockType POTTED_ORANGE_TULIP = get("minecraft:potted_orange_tulip"); @Nullable public static final BlockType POTTED_OXEYE_DAISY = get("minecraft:potted_oxeye_daisy"); @@ -458,6 +515,7 @@ public final class BlockTypes { @Nullable public static final BlockType POTTED_RED_TULIP = get("minecraft:potted_red_tulip"); @Nullable public static final BlockType POTTED_SPRUCE_SAPLING = get("minecraft:potted_spruce_sapling"); @Nullable public static final BlockType POTTED_WHITE_TULIP = get("minecraft:potted_white_tulip"); + @Nullable public static final BlockType POTTED_WITHER_ROSE = get("minecraft:potted_wither_rose"); @Nullable public static final BlockType POWERED_RAIL = get("minecraft:powered_rail"); @Nullable public static final BlockType PRISMARINE = get("minecraft:prismarine"); @Nullable public static final BlockType PRISMARINE_BRICK_SLAB = get("minecraft:prismarine_brick_slab"); @@ -465,6 +523,7 @@ public final class BlockTypes { @Nullable public static final BlockType PRISMARINE_BRICKS = get("minecraft:prismarine_bricks"); @Nullable public static final BlockType PRISMARINE_SLAB = get("minecraft:prismarine_slab"); @Nullable public static final BlockType PRISMARINE_STAIRS = get("minecraft:prismarine_stairs"); + @Nullable public static final BlockType PRISMARINE_WALL = get("minecraft:prismarine_wall"); @Nullable public static final BlockType PUMPKIN = get("minecraft:pumpkin"); @Nullable public static final BlockType PUMPKIN_STEM = get("minecraft:pumpkin_stem"); @Nullable public static final BlockType PURPLE_BANNER = get("minecraft:purple_banner"); @@ -496,11 +555,15 @@ public final class BlockTypes { @Nullable public static final BlockType RED_GLAZED_TERRACOTTA = get("minecraft:red_glazed_terracotta"); @Nullable public static final BlockType RED_MUSHROOM = get("minecraft:red_mushroom"); @Nullable public static final BlockType RED_MUSHROOM_BLOCK = get("minecraft:red_mushroom_block"); + @Nullable public static final BlockType RED_NETHER_BRICK_SLAB = get("minecraft:red_nether_brick_slab"); + @Nullable public static final BlockType RED_NETHER_BRICK_STAIRS = get("minecraft:red_nether_brick_stairs"); + @Nullable public static final BlockType RED_NETHER_BRICK_WALL = get("minecraft:red_nether_brick_wall"); @Nullable public static final BlockType RED_NETHER_BRICKS = get("minecraft:red_nether_bricks"); @Nullable public static final BlockType RED_SAND = get("minecraft:red_sand"); @Nullable public static final BlockType RED_SANDSTONE = get("minecraft:red_sandstone"); @Nullable public static final BlockType RED_SANDSTONE_SLAB = get("minecraft:red_sandstone_slab"); @Nullable public static final BlockType RED_SANDSTONE_STAIRS = get("minecraft:red_sandstone_stairs"); + @Nullable public static final BlockType RED_SANDSTONE_WALL = get("minecraft:red_sandstone_wall"); @Nullable public static final BlockType RED_SHULKER_BOX = get("minecraft:red_shulker_box"); @Nullable public static final BlockType RED_STAINED_GLASS = get("minecraft:red_stained_glass"); @Nullable public static final BlockType RED_STAINED_GLASS_PANE = get("minecraft:red_stained_glass_pane"); @@ -521,18 +584,29 @@ public final class BlockTypes { @Nullable public static final BlockType SANDSTONE = get("minecraft:sandstone"); @Nullable public static final BlockType SANDSTONE_SLAB = get("minecraft:sandstone_slab"); @Nullable public static final BlockType SANDSTONE_STAIRS = get("minecraft:sandstone_stairs"); + @Nullable public static final BlockType SANDSTONE_WALL = get("minecraft:sandstone_wall"); + @Nullable public static final BlockType SCAFFOLDING = get("minecraft:scaffolding"); @Nullable public static final BlockType SEA_LANTERN = get("minecraft:sea_lantern"); @Nullable public static final BlockType SEA_PICKLE = get("minecraft:sea_pickle"); @Nullable public static final BlockType SEAGRASS = get("minecraft:seagrass"); @Nullable public static final BlockType SHULKER_BOX = get("minecraft:shulker_box"); - @Nullable public static final BlockType SIGN = get("minecraft:sign"); + @Deprecated @Nullable public static final BlockType SIGN = Optional.ofNullable(get("minecraft:sign")).orElse(get("minecraft:oak_sign")); @Nullable public static final BlockType SKELETON_SKULL = get("minecraft:skeleton_skull"); @Nullable public static final BlockType SKELETON_WALL_SKULL = get("minecraft:skeleton_wall_skull"); @Nullable public static final BlockType SLIME_BLOCK = get("minecraft:slime_block"); + @Nullable public static final BlockType SMITHING_TABLE = get("minecraft:smithing_table"); + @Nullable public static final BlockType SMOKER = get("minecraft:smoker"); @Nullable public static final BlockType SMOOTH_QUARTZ = get("minecraft:smooth_quartz"); + @Nullable public static final BlockType SMOOTH_QUARTZ_SLAB = get("minecraft:smooth_quartz_slab"); + @Nullable public static final BlockType SMOOTH_QUARTZ_STAIRS = get("minecraft:smooth_quartz_stairs"); @Nullable public static final BlockType SMOOTH_RED_SANDSTONE = get("minecraft:smooth_red_sandstone"); + @Nullable public static final BlockType SMOOTH_RED_SANDSTONE_SLAB = get("minecraft:smooth_red_sandstone_slab"); + @Nullable public static final BlockType SMOOTH_RED_SANDSTONE_STAIRS = get("minecraft:smooth_red_sandstone_stairs"); @Nullable public static final BlockType SMOOTH_SANDSTONE = get("minecraft:smooth_sandstone"); + @Nullable public static final BlockType SMOOTH_SANDSTONE_SLAB = get("minecraft:smooth_sandstone_slab"); + @Nullable public static final BlockType SMOOTH_SANDSTONE_STAIRS = get("minecraft:smooth_sandstone_stairs"); @Nullable public static final BlockType SMOOTH_STONE = get("minecraft:smooth_stone"); + @Nullable public static final BlockType SMOOTH_STONE_SLAB = get("minecraft:smooth_stone_slab"); @Nullable public static final BlockType SNOW = get("minecraft:snow"); @Nullable public static final BlockType SNOW_BLOCK = get("minecraft:snow_block"); @Nullable public static final BlockType SOUL_SAND = get("minecraft:soul_sand"); @@ -547,18 +621,23 @@ public final class BlockTypes { @Nullable public static final BlockType SPRUCE_PLANKS = get("minecraft:spruce_planks"); @Nullable public static final BlockType SPRUCE_PRESSURE_PLATE = get("minecraft:spruce_pressure_plate"); @Nullable public static final BlockType SPRUCE_SAPLING = get("minecraft:spruce_sapling"); + @Nullable public static final BlockType SPRUCE_SIGN = get("minecraft:spruce_sign"); @Nullable public static final BlockType SPRUCE_SLAB = get("minecraft:spruce_slab"); @Nullable public static final BlockType SPRUCE_STAIRS = get("minecraft:spruce_stairs"); @Nullable public static final BlockType SPRUCE_TRAPDOOR = get("minecraft:spruce_trapdoor"); + @Nullable public static final BlockType SPRUCE_WALL_SIGN = get("minecraft:spruce_wall_sign"); @Nullable public static final BlockType SPRUCE_WOOD = get("minecraft:spruce_wood"); @Nullable public static final BlockType STICKY_PISTON = get("minecraft:sticky_piston"); @Nullable public static final BlockType STONE = get("minecraft:stone"); @Nullable public static final BlockType STONE_BRICK_SLAB = get("minecraft:stone_brick_slab"); @Nullable public static final BlockType STONE_BRICK_STAIRS = get("minecraft:stone_brick_stairs"); + @Nullable public static final BlockType STONE_BRICK_WALL = get("minecraft:stone_brick_wall"); @Nullable public static final BlockType STONE_BRICKS = get("minecraft:stone_bricks"); @Nullable public static final BlockType STONE_BUTTON = get("minecraft:stone_button"); @Nullable public static final BlockType STONE_PRESSURE_PLATE = get("minecraft:stone_pressure_plate"); @Nullable public static final BlockType STONE_SLAB = get("minecraft:stone_slab"); + @Nullable public static final BlockType STONE_STAIRS = get("minecraft:stone_stairs"); + @Nullable public static final BlockType STONECUTTER = get("minecraft:stonecutter"); @Nullable public static final BlockType STRIPPED_ACACIA_LOG = get("minecraft:stripped_acacia_log"); @Nullable public static final BlockType STRIPPED_ACACIA_WOOD = get("minecraft:stripped_acacia_wood"); @Nullable public static final BlockType STRIPPED_BIRCH_LOG = get("minecraft:stripped_birch_log"); @@ -575,6 +654,7 @@ public final class BlockTypes { @Nullable public static final BlockType STRUCTURE_VOID = get("minecraft:structure_void"); @Nullable public static final BlockType SUGAR_CANE = get("minecraft:sugar_cane"); @Nullable public static final BlockType SUNFLOWER = get("minecraft:sunflower"); + @Nullable public static final BlockType SWEET_BERRY_BUSH = get("minecraft:sweet_berry_bush"); @Nullable public static final BlockType TALL_GRASS = get("minecraft:tall_grass"); @Nullable public static final BlockType TALL_SEAGRASS = get("minecraft:tall_seagrass"); @Nullable public static final BlockType TERRACOTTA = get("minecraft:terracotta"); @@ -590,7 +670,7 @@ public final class BlockTypes { @Nullable public static final BlockType TURTLE_EGG = get("minecraft:turtle_egg"); @Nullable public static final BlockType VINE = get("minecraft:vine"); @Nullable public static final BlockType VOID_AIR = get("minecraft:void_air"); - @Nullable public static final BlockType WALL_SIGN = get("minecraft:wall_sign"); + @Deprecated @Nullable public static final BlockType WALL_SIGN = Optional.ofNullable(get("minecraft:wall_sign")).orElse(get("minecraft:oak_wall_sign")); @Nullable public static final BlockType WALL_TORCH = get("minecraft:wall_torch"); @Nullable public static final BlockType WATER = get("minecraft:water"); @Nullable public static final BlockType WET_SPONGE = get("minecraft:wet_sponge"); @@ -608,6 +688,7 @@ public final class BlockTypes { @Nullable public static final BlockType WHITE_TULIP = get("minecraft:white_tulip"); @Nullable public static final BlockType WHITE_WALL_BANNER = get("minecraft:white_wall_banner"); @Nullable public static final BlockType WHITE_WOOL = get("minecraft:white_wool"); + @Nullable public static final BlockType WITHER_ROSE = get("minecraft:wither_rose"); @Nullable public static final BlockType WITHER_SKELETON_SKULL = get("minecraft:wither_skeleton_skull"); @Nullable public static final BlockType WITHER_SKELETON_WALL_SKULL = get("minecraft:wither_skeleton_wall_skull"); @Nullable public static final BlockType YELLOW_BANNER = get("minecraft:yellow_banner"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java index f98fd96c2..36b6831ae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/entity/EntityTypes.java @@ -29,6 +29,7 @@ public class EntityTypes { @Nullable public static final EntityType BAT = get("minecraft:bat"); @Nullable public static final EntityType BLAZE = get("minecraft:blaze"); @Nullable public static final EntityType BOAT = get("minecraft:boat"); + @Nullable public static final EntityType CAT = get("minecraft:cat"); @Nullable public static final EntityType CAVE_SPIDER = get("minecraft:cave_spider"); @Nullable public static final EntityType CHEST_MINECART = get("minecraft:chest_minecart"); @Nullable public static final EntityType CHICKEN = get("minecraft:chicken"); @@ -56,6 +57,7 @@ public class EntityTypes { @Nullable public static final EntityType FIREBALL = get("minecraft:fireball"); @Nullable public static final EntityType FIREWORK_ROCKET = get("minecraft:firework_rocket"); @Nullable public static final EntityType FISHING_BOBBER = get("minecraft:fishing_bobber"); + @Nullable public static final EntityType FOX = get("minecraft:fox"); @Nullable public static final EntityType FURNACE_MINECART = get("minecraft:furnace_minecart"); @Nullable public static final EntityType GHAST = get("minecraft:ghast"); @Nullable public static final EntityType GIANT = get("minecraft:giant"); @@ -77,14 +79,17 @@ public class EntityTypes { @Nullable public static final EntityType MULE = get("minecraft:mule"); @Nullable public static final EntityType OCELOT = get("minecraft:ocelot"); @Nullable public static final EntityType PAINTING = get("minecraft:painting"); + @Nullable public static final EntityType PANDA = get("minecraft:panda"); @Nullable public static final EntityType PARROT = get("minecraft:parrot"); @Nullable public static final EntityType PHANTOM = get("minecraft:phantom"); @Nullable public static final EntityType PIG = get("minecraft:pig"); + @Nullable public static final EntityType PILLAGER = get("minecraft:pillager"); @Nullable public static final EntityType PLAYER = get("minecraft:player"); @Nullable public static final EntityType POLAR_BEAR = get("minecraft:polar_bear"); @Nullable public static final EntityType POTION = get("minecraft:potion"); @Nullable public static final EntityType PUFFERFISH = get("minecraft:pufferfish"); @Nullable public static final EntityType RABBIT = get("minecraft:rabbit"); + @Nullable public static final EntityType RAVAGER = get("minecraft:ravager"); @Nullable public static final EntityType SALMON = get("minecraft:salmon"); @Nullable public static final EntityType SHEEP = get("minecraft:sheep"); @Nullable public static final EntityType SHULKER = get("minecraft:shulker"); @@ -103,12 +108,14 @@ public class EntityTypes { @Nullable public static final EntityType STRAY = get("minecraft:stray"); @Nullable public static final EntityType TNT = get("minecraft:tnt"); @Nullable public static final EntityType TNT_MINECART = get("minecraft:tnt_minecart"); + @Nullable public static final EntityType TRADER_LLAMA = get("minecraft:trader_llama"); @Nullable public static final EntityType TRIDENT = get("minecraft:trident"); @Nullable public static final EntityType TROPICAL_FISH = get("minecraft:tropical_fish"); @Nullable public static final EntityType TURTLE = get("minecraft:turtle"); @Nullable public static final EntityType VEX = get("minecraft:vex"); @Nullable public static final EntityType VILLAGER = get("minecraft:villager"); @Nullable public static final EntityType VINDICATOR = get("minecraft:vindicator"); + @Nullable public static final EntityType WANDERING_TRADER = get("minecraft:wandering_trader"); @Nullable public static final EntityType WITCH = get("minecraft:witch"); @Nullable public static final EntityType WITHER = get("minecraft:wither"); @Nullable public static final EntityType WITHER_SKELETON = get("minecraft:wither_skeleton"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java index 021d6834c..7dd006871 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemCategories.java @@ -26,33 +26,42 @@ public final class ItemCategories { public static final ItemCategory ACACIA_LOGS = get("minecraft:acacia_logs"); public static final ItemCategory ANVIL = get("minecraft:anvil"); + public static final ItemCategory ARROWS = get("minecraft:arrows"); public static final ItemCategory BANNERS = get("minecraft:banners"); + public static final ItemCategory BEDS = get("minecraft:beds"); public static final ItemCategory BIRCH_LOGS = get("minecraft:birch_logs"); public static final ItemCategory BOATS = get("minecraft:boats"); public static final ItemCategory BUTTONS = get("minecraft:buttons"); public static final ItemCategory CARPETS = get("minecraft:carpets"); - public static final ItemCategory CORAL = get("minecraft:coral"); - public static final ItemCategory CORAL_PLANTS = get("minecraft:coral_plants"); + public static final ItemCategory COALS = get("minecraft:coals"); public static final ItemCategory DARK_OAK_LOGS = get("minecraft:dark_oak_logs"); public static final ItemCategory DOORS = get("minecraft:doors"); + public static final ItemCategory FENCES = get("minecraft:fences"); public static final ItemCategory FISHES = get("minecraft:fishes"); public static final ItemCategory JUNGLE_LOGS = get("minecraft:jungle_logs"); public static final ItemCategory LEAVES = get("minecraft:leaves"); public static final ItemCategory LOGS = get("minecraft:logs"); + public static final ItemCategory MUSIC_DISCS = get("minecraft:music_discs"); public static final ItemCategory OAK_LOGS = get("minecraft:oak_logs"); public static final ItemCategory PLANKS = get("minecraft:planks"); public static final ItemCategory RAILS = get("minecraft:rails"); public static final ItemCategory SAND = get("minecraft:sand"); public static final ItemCategory SAPLINGS = get("minecraft:saplings"); + public static final ItemCategory SIGNS = get("minecraft:signs"); public static final ItemCategory SLABS = get("minecraft:slabs"); + public static final ItemCategory SMALL_FLOWERS = get("minecraft:small_flowers"); public static final ItemCategory SPRUCE_LOGS = get("minecraft:spruce_logs"); public static final ItemCategory STAIRS = get("minecraft:stairs"); public static final ItemCategory STONE_BRICKS = get("minecraft:stone_bricks"); + public static final ItemCategory TRAPDOORS = get("minecraft:trapdoors"); + public static final ItemCategory WALLS = get("minecraft:walls"); public static final ItemCategory WOODEN_BUTTONS = get("minecraft:wooden_buttons"); public static final ItemCategory WOODEN_DOORS = get("minecraft:wooden_doors"); + public static final ItemCategory WOODEN_FENCES = get("minecraft:wooden_fences"); public static final ItemCategory WOODEN_PRESSURE_PLATES = get("minecraft:wooden_pressure_plates"); public static final ItemCategory WOODEN_SLABS = get("minecraft:wooden_slabs"); public static final ItemCategory WOODEN_STAIRS = get("minecraft:wooden_stairs"); + public static final ItemCategory WOODEN_TRAPDOORS = get("minecraft:wooden_trapdoors"); public static final ItemCategory WOOL = get("minecraft:wool"); private ItemCategories() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java index 677ed2a8e..e773a4f6d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/item/ItemTypes.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.world.item; import javax.annotation.Nullable; +import java.util.Optional; public final class ItemTypes { @@ -33,6 +34,7 @@ public final class ItemTypes { @Nullable public static final ItemType ACACIA_PLANKS = get("minecraft:acacia_planks"); @Nullable public static final ItemType ACACIA_PRESSURE_PLATE = get("minecraft:acacia_pressure_plate"); @Nullable public static final ItemType ACACIA_SAPLING = get("minecraft:acacia_sapling"); + @Nullable public static final ItemType ACACIA_SIGN = get("minecraft:acacia_sign"); @Nullable public static final ItemType ACACIA_SLAB = get("minecraft:acacia_slab"); @Nullable public static final ItemType ACACIA_STAIRS = get("minecraft:acacia_stairs"); @Nullable public static final ItemType ACACIA_TRAPDOOR = get("minecraft:acacia_trapdoor"); @@ -41,12 +43,17 @@ public final class ItemTypes { @Nullable public static final ItemType AIR = get("minecraft:air"); @Nullable public static final ItemType ALLIUM = get("minecraft:allium"); @Nullable public static final ItemType ANDESITE = get("minecraft:andesite"); + @Nullable public static final ItemType ANDESITE_SLAB = get("minecraft:andesite_slab"); + @Nullable public static final ItemType ANDESITE_STAIRS = get("minecraft:andesite_stairs"); + @Nullable public static final ItemType ANDESITE_WALL = get("minecraft:andesite_wall"); @Nullable public static final ItemType ANVIL = get("minecraft:anvil"); @Nullable public static final ItemType APPLE = get("minecraft:apple"); @Nullable public static final ItemType ARMOR_STAND = get("minecraft:armor_stand"); @Nullable public static final ItemType ARROW = get("minecraft:arrow"); @Nullable public static final ItemType AZURE_BLUET = get("minecraft:azure_bluet"); @Nullable public static final ItemType BAKED_POTATO = get("minecraft:baked_potato"); + @Nullable public static final ItemType BAMBOO = get("minecraft:bamboo"); + @Nullable public static final ItemType BARREL = get("minecraft:barrel"); @Nullable public static final ItemType BARRIER = get("minecraft:barrier"); @Nullable public static final ItemType BAT_SPAWN_EGG = get("minecraft:bat_spawn_egg"); @Nullable public static final ItemType BEACON = get("minecraft:beacon"); @@ -55,6 +62,7 @@ public final class ItemTypes { @Nullable public static final ItemType BEETROOT = get("minecraft:beetroot"); @Nullable public static final ItemType BEETROOT_SEEDS = get("minecraft:beetroot_seeds"); @Nullable public static final ItemType BEETROOT_SOUP = get("minecraft:beetroot_soup"); + @Nullable public static final ItemType BELL = get("minecraft:bell"); @Nullable public static final ItemType BIRCH_BOAT = get("minecraft:birch_boat"); @Nullable public static final ItemType BIRCH_BUTTON = get("minecraft:birch_button"); @Nullable public static final ItemType BIRCH_DOOR = get("minecraft:birch_door"); @@ -65,6 +73,7 @@ public final class ItemTypes { @Nullable public static final ItemType BIRCH_PLANKS = get("minecraft:birch_planks"); @Nullable public static final ItemType BIRCH_PRESSURE_PLATE = get("minecraft:birch_pressure_plate"); @Nullable public static final ItemType BIRCH_SAPLING = get("minecraft:birch_sapling"); + @Nullable public static final ItemType BIRCH_SIGN = get("minecraft:birch_sign"); @Nullable public static final ItemType BIRCH_SLAB = get("minecraft:birch_slab"); @Nullable public static final ItemType BIRCH_STAIRS = get("minecraft:birch_stairs"); @Nullable public static final ItemType BIRCH_TRAPDOOR = get("minecraft:birch_trapdoor"); @@ -74,12 +83,14 @@ public final class ItemTypes { @Nullable public static final ItemType BLACK_CARPET = get("minecraft:black_carpet"); @Nullable public static final ItemType BLACK_CONCRETE = get("minecraft:black_concrete"); @Nullable public static final ItemType BLACK_CONCRETE_POWDER = get("minecraft:black_concrete_powder"); + @Nullable public static final ItemType BLACK_DYE = get("minecraft:black_dye"); @Nullable public static final ItemType BLACK_GLAZED_TERRACOTTA = get("minecraft:black_glazed_terracotta"); @Nullable public static final ItemType BLACK_SHULKER_BOX = get("minecraft:black_shulker_box"); @Nullable public static final ItemType BLACK_STAINED_GLASS = get("minecraft:black_stained_glass"); @Nullable public static final ItemType BLACK_STAINED_GLASS_PANE = get("minecraft:black_stained_glass_pane"); @Nullable public static final ItemType BLACK_TERRACOTTA = get("minecraft:black_terracotta"); @Nullable public static final ItemType BLACK_WOOL = get("minecraft:black_wool"); + @Nullable public static final ItemType BLAST_FURNACE = get("minecraft:blast_furnace"); @Nullable public static final ItemType BLAZE_POWDER = get("minecraft:blaze_powder"); @Nullable public static final ItemType BLAZE_ROD = get("minecraft:blaze_rod"); @Nullable public static final ItemType BLAZE_SPAWN_EGG = get("minecraft:blaze_spawn_egg"); @@ -88,6 +99,7 @@ public final class ItemTypes { @Nullable public static final ItemType BLUE_CARPET = get("minecraft:blue_carpet"); @Nullable public static final ItemType BLUE_CONCRETE = get("minecraft:blue_concrete"); @Nullable public static final ItemType BLUE_CONCRETE_POWDER = get("minecraft:blue_concrete_powder"); + @Nullable public static final ItemType BLUE_DYE = get("minecraft:blue_dye"); @Nullable public static final ItemType BLUE_GLAZED_TERRACOTTA = get("minecraft:blue_glazed_terracotta"); @Nullable public static final ItemType BLUE_ICE = get("minecraft:blue_ice"); @Nullable public static final ItemType BLUE_ORCHID = get("minecraft:blue_orchid"); @@ -111,12 +123,14 @@ public final class ItemTypes { @Nullable public static final ItemType BRICK = get("minecraft:brick"); @Nullable public static final ItemType BRICK_SLAB = get("minecraft:brick_slab"); @Nullable public static final ItemType BRICK_STAIRS = get("minecraft:brick_stairs"); + @Nullable public static final ItemType BRICK_WALL = get("minecraft:brick_wall"); @Nullable public static final ItemType BRICKS = get("minecraft:bricks"); @Nullable public static final ItemType BROWN_BANNER = get("minecraft:brown_banner"); @Nullable public static final ItemType BROWN_BED = get("minecraft:brown_bed"); @Nullable public static final ItemType BROWN_CARPET = get("minecraft:brown_carpet"); @Nullable public static final ItemType BROWN_CONCRETE = get("minecraft:brown_concrete"); @Nullable public static final ItemType BROWN_CONCRETE_POWDER = get("minecraft:brown_concrete_powder"); + @Nullable public static final ItemType BROWN_DYE = get("minecraft:brown_dye"); @Nullable public static final ItemType BROWN_GLAZED_TERRACOTTA = get("minecraft:brown_glazed_terracotta"); @Nullable public static final ItemType BROWN_MUSHROOM = get("minecraft:brown_mushroom"); @Nullable public static final ItemType BROWN_MUSHROOM_BLOCK = get("minecraft:brown_mushroom_block"); @@ -130,11 +144,14 @@ public final class ItemTypes { @Nullable public static final ItemType BUBBLE_CORAL_FAN = get("minecraft:bubble_coral_fan"); @Nullable public static final ItemType BUCKET = get("minecraft:bucket"); @Nullable public static final ItemType CACTUS = get("minecraft:cactus"); - @Nullable public static final ItemType CACTUS_GREEN = get("minecraft:cactus_green"); + @Deprecated @Nullable public static final ItemType CACTUS_GREEN = Optional.ofNullable(get("minecraft:cactus_green")).orElseGet(() -> get("minecraft:green_dye")); @Nullable public static final ItemType CAKE = get("minecraft:cake"); + @Nullable public static final ItemType CAMPFIRE = get("minecraft:campfire"); @Nullable public static final ItemType CARROT = get("minecraft:carrot"); @Nullable public static final ItemType CARROT_ON_A_STICK = get("minecraft:carrot_on_a_stick"); + @Nullable public static final ItemType CARTOGRAPHY_TABLE = get("minecraft:cartography_table"); @Nullable public static final ItemType CARVED_PUMPKIN = get("minecraft:carved_pumpkin"); + @Nullable public static final ItemType CAT_SPAWN_EGG = get("minecraft:cat_spawn_egg"); @Nullable public static final ItemType CAULDRON = get("minecraft:cauldron"); @Nullable public static final ItemType CAVE_SPIDER_SPAWN_EGG = get("minecraft:cave_spider_spawn_egg"); @Nullable public static final ItemType CHAIN_COMMAND_BLOCK = get("minecraft:chain_command_block"); @@ -175,6 +192,7 @@ public final class ItemTypes { @Nullable public static final ItemType COMMAND_BLOCK_MINECART = get("minecraft:command_block_minecart"); @Nullable public static final ItemType COMPARATOR = get("minecraft:comparator"); @Nullable public static final ItemType COMPASS = get("minecraft:compass"); + @Nullable public static final ItemType COMPOSTER = get("minecraft:composter"); @Nullable public static final ItemType CONDUIT = get("minecraft:conduit"); @Nullable public static final ItemType COOKED_BEEF = get("minecraft:cooked_beef"); @Nullable public static final ItemType COOKED_CHICKEN = get("minecraft:cooked_chicken"); @@ -184,13 +202,18 @@ public final class ItemTypes { @Nullable public static final ItemType COOKED_RABBIT = get("minecraft:cooked_rabbit"); @Nullable public static final ItemType COOKED_SALMON = get("minecraft:cooked_salmon"); @Nullable public static final ItemType COOKIE = get("minecraft:cookie"); + @Nullable public static final ItemType CORNFLOWER = get("minecraft:cornflower"); @Nullable public static final ItemType COW_SPAWN_EGG = get("minecraft:cow_spawn_egg"); @Nullable public static final ItemType CRACKED_STONE_BRICKS = get("minecraft:cracked_stone_bricks"); @Nullable public static final ItemType CRAFTING_TABLE = get("minecraft:crafting_table"); + @Nullable public static final ItemType CREEPER_BANNER_PATTERN = get("minecraft:creeper_banner_pattern"); @Nullable public static final ItemType CREEPER_HEAD = get("minecraft:creeper_head"); @Nullable public static final ItemType CREEPER_SPAWN_EGG = get("minecraft:creeper_spawn_egg"); + @Nullable public static final ItemType CROSSBOW = get("minecraft:crossbow"); @Nullable public static final ItemType CUT_RED_SANDSTONE = get("minecraft:cut_red_sandstone"); + @Nullable public static final ItemType CUT_RED_SANDSTONE_SLAB = get("minecraft:cut_red_sandstone_slab"); @Nullable public static final ItemType CUT_SANDSTONE = get("minecraft:cut_sandstone"); + @Nullable public static final ItemType CUT_SANDSTONE_SLAB = get("minecraft:cut_sandstone_slab"); @Nullable public static final ItemType CYAN_BANNER = get("minecraft:cyan_banner"); @Nullable public static final ItemType CYAN_BED = get("minecraft:cyan_bed"); @Nullable public static final ItemType CYAN_CARPET = get("minecraft:cyan_carpet"); @@ -205,7 +228,7 @@ public final class ItemTypes { @Nullable public static final ItemType CYAN_WOOL = get("minecraft:cyan_wool"); @Nullable public static final ItemType DAMAGED_ANVIL = get("minecraft:damaged_anvil"); @Nullable public static final ItemType DANDELION = get("minecraft:dandelion"); - @Nullable public static final ItemType DANDELION_YELLOW = get("minecraft:dandelion_yellow"); + @Deprecated @Nullable public static final ItemType DANDELION_YELLOW = Optional.ofNullable(get("minecraft:dandelion_yellow")).orElseGet(() -> (get("minecraft:yellow_dye"))); @Nullable public static final ItemType DARK_OAK_BOAT = get("minecraft:dark_oak_boat"); @Nullable public static final ItemType DARK_OAK_BUTTON = get("minecraft:dark_oak_button"); @Nullable public static final ItemType DARK_OAK_DOOR = get("minecraft:dark_oak_door"); @@ -216,6 +239,7 @@ public final class ItemTypes { @Nullable public static final ItemType DARK_OAK_PLANKS = get("minecraft:dark_oak_planks"); @Nullable public static final ItemType DARK_OAK_PRESSURE_PLATE = get("minecraft:dark_oak_pressure_plate"); @Nullable public static final ItemType DARK_OAK_SAPLING = get("minecraft:dark_oak_sapling"); + @Nullable public static final ItemType DARK_OAK_SIGN = get("minecraft:dark_oak_sign"); @Nullable public static final ItemType DARK_OAK_SLAB = get("minecraft:dark_oak_slab"); @Nullable public static final ItemType DARK_OAK_STAIRS = get("minecraft:dark_oak_stairs"); @Nullable public static final ItemType DARK_OAK_TRAPDOOR = get("minecraft:dark_oak_trapdoor"); @@ -256,6 +280,9 @@ public final class ItemTypes { @Nullable public static final ItemType DIAMOND_SHOVEL = get("minecraft:diamond_shovel"); @Nullable public static final ItemType DIAMOND_SWORD = get("minecraft:diamond_sword"); @Nullable public static final ItemType DIORITE = get("minecraft:diorite"); + @Nullable public static final ItemType DIORITE_SLAB = get("minecraft:diorite_slab"); + @Nullable public static final ItemType DIORITE_STAIRS = get("minecraft:diorite_stairs"); + @Nullable public static final ItemType DIORITE_WALL = get("minecraft:diorite_wall"); @Nullable public static final ItemType DIRT = get("minecraft:dirt"); @Nullable public static final ItemType DISPENSER = get("minecraft:dispenser"); @Nullable public static final ItemType DOLPHIN_SPAWN_EGG = get("minecraft:dolphin_spawn_egg"); @@ -280,6 +307,9 @@ public final class ItemTypes { @Nullable public static final ItemType END_PORTAL_FRAME = get("minecraft:end_portal_frame"); @Nullable public static final ItemType END_ROD = get("minecraft:end_rod"); @Nullable public static final ItemType END_STONE = get("minecraft:end_stone"); + @Nullable public static final ItemType END_STONE_BRICK_SLAB = get("minecraft:end_stone_brick_slab"); + @Nullable public static final ItemType END_STONE_BRICK_STAIRS = get("minecraft:end_stone_brick_stairs"); + @Nullable public static final ItemType END_STONE_BRICK_WALL = get("minecraft:end_stone_brick_wall"); @Nullable public static final ItemType END_STONE_BRICKS = get("minecraft:end_stone_bricks"); @Nullable public static final ItemType ENDER_CHEST = get("minecraft:ender_chest"); @Nullable public static final ItemType ENDER_EYE = get("minecraft:ender_eye"); @@ -300,9 +330,12 @@ public final class ItemTypes { @Nullable public static final ItemType FIREWORK_ROCKET = get("minecraft:firework_rocket"); @Nullable public static final ItemType FIREWORK_STAR = get("minecraft:firework_star"); @Nullable public static final ItemType FISHING_ROD = get("minecraft:fishing_rod"); + @Nullable public static final ItemType FLETCHING_TABLE = get("minecraft:fletching_table"); @Nullable public static final ItemType FLINT = get("minecraft:flint"); @Nullable public static final ItemType FLINT_AND_STEEL = get("minecraft:flint_and_steel"); + @Nullable public static final ItemType FLOWER_BANNER_PATTERN = get("minecraft:flower_banner_pattern"); @Nullable public static final ItemType FLOWER_POT = get("minecraft:flower_pot"); + @Nullable public static final ItemType FOX_SPAWN_EGG = get("minecraft:fox_spawn_egg"); @Nullable public static final ItemType FURNACE = get("minecraft:furnace"); @Nullable public static final ItemType FURNACE_MINECART = get("minecraft:furnace_minecart"); @Nullable public static final ItemType GHAST_SPAWN_EGG = get("minecraft:ghast_spawn_egg"); @@ -311,6 +344,7 @@ public final class ItemTypes { @Nullable public static final ItemType GLASS_BOTTLE = get("minecraft:glass_bottle"); @Nullable public static final ItemType GLASS_PANE = get("minecraft:glass_pane"); @Nullable public static final ItemType GLISTERING_MELON_SLICE = get("minecraft:glistering_melon_slice"); + @Nullable public static final ItemType GLOBE_BANNER_PATTERN = get("minecraft:globe_banner_pattern"); @Nullable public static final ItemType GLOWSTONE = get("minecraft:glowstone"); @Nullable public static final ItemType GLOWSTONE_DUST = get("minecraft:glowstone_dust"); @Nullable public static final ItemType GOLD_BLOCK = get("minecraft:gold_block"); @@ -330,6 +364,9 @@ public final class ItemTypes { @Nullable public static final ItemType GOLDEN_SHOVEL = get("minecraft:golden_shovel"); @Nullable public static final ItemType GOLDEN_SWORD = get("minecraft:golden_sword"); @Nullable public static final ItemType GRANITE = get("minecraft:granite"); + @Nullable public static final ItemType GRANITE_SLAB = get("minecraft:granite_slab"); + @Nullable public static final ItemType GRANITE_STAIRS = get("minecraft:granite_stairs"); + @Nullable public static final ItemType GRANITE_WALL = get("minecraft:granite_wall"); @Nullable public static final ItemType GRASS = get("minecraft:grass"); @Nullable public static final ItemType GRASS_BLOCK = get("minecraft:grass_block"); @Nullable public static final ItemType GRASS_PATH = get("minecraft:grass_path"); @@ -351,12 +388,14 @@ public final class ItemTypes { @Nullable public static final ItemType GREEN_CARPET = get("minecraft:green_carpet"); @Nullable public static final ItemType GREEN_CONCRETE = get("minecraft:green_concrete"); @Nullable public static final ItemType GREEN_CONCRETE_POWDER = get("minecraft:green_concrete_powder"); + @Nullable public static final ItemType GREEN_DYE = get("minecraft:green_dye"); @Nullable public static final ItemType GREEN_GLAZED_TERRACOTTA = get("minecraft:green_glazed_terracotta"); @Nullable public static final ItemType GREEN_SHULKER_BOX = get("minecraft:green_shulker_box"); @Nullable public static final ItemType GREEN_STAINED_GLASS = get("minecraft:green_stained_glass"); @Nullable public static final ItemType GREEN_STAINED_GLASS_PANE = get("minecraft:green_stained_glass_pane"); @Nullable public static final ItemType GREEN_TERRACOTTA = get("minecraft:green_terracotta"); @Nullable public static final ItemType GREEN_WOOL = get("minecraft:green_wool"); + @Nullable public static final ItemType GRINDSTONE = get("minecraft:grindstone"); @Nullable public static final ItemType GUARDIAN_SPAWN_EGG = get("minecraft:guardian_spawn_egg"); @Nullable public static final ItemType GUNPOWDER = get("minecraft:gunpowder"); @Nullable public static final ItemType HAY_BLOCK = get("minecraft:hay_block"); @@ -396,6 +435,7 @@ public final class ItemTypes { @Nullable public static final ItemType IRON_TRAPDOOR = get("minecraft:iron_trapdoor"); @Nullable public static final ItemType ITEM_FRAME = get("minecraft:item_frame"); @Nullable public static final ItemType JACK_O_LANTERN = get("minecraft:jack_o_lantern"); + @Nullable public static final ItemType JIGSAW = get("minecraft:jigsaw"); @Nullable public static final ItemType JUKEBOX = get("minecraft:jukebox"); @Nullable public static final ItemType JUNGLE_BOAT = get("minecraft:jungle_boat"); @Nullable public static final ItemType JUNGLE_BUTTON = get("minecraft:jungle_button"); @@ -407,6 +447,7 @@ public final class ItemTypes { @Nullable public static final ItemType JUNGLE_PLANKS = get("minecraft:jungle_planks"); @Nullable public static final ItemType JUNGLE_PRESSURE_PLATE = get("minecraft:jungle_pressure_plate"); @Nullable public static final ItemType JUNGLE_SAPLING = get("minecraft:jungle_sapling"); + @Nullable public static final ItemType JUNGLE_SIGN = get("minecraft:jungle_sign"); @Nullable public static final ItemType JUNGLE_SLAB = get("minecraft:jungle_slab"); @Nullable public static final ItemType JUNGLE_STAIRS = get("minecraft:jungle_stairs"); @Nullable public static final ItemType JUNGLE_TRAPDOOR = get("minecraft:jungle_trapdoor"); @@ -414,6 +455,7 @@ public final class ItemTypes { @Nullable public static final ItemType KELP = get("minecraft:kelp"); @Nullable public static final ItemType KNOWLEDGE_BOOK = get("minecraft:knowledge_book"); @Nullable public static final ItemType LADDER = get("minecraft:ladder"); + @Nullable public static final ItemType LANTERN = get("minecraft:lantern"); @Nullable public static final ItemType LAPIS_BLOCK = get("minecraft:lapis_block"); @Nullable public static final ItemType LAPIS_LAZULI = get("minecraft:lapis_lazuli"); @Nullable public static final ItemType LAPIS_ORE = get("minecraft:lapis_ore"); @@ -424,7 +466,9 @@ public final class ItemTypes { @Nullable public static final ItemType LEATHER_BOOTS = get("minecraft:leather_boots"); @Nullable public static final ItemType LEATHER_CHESTPLATE = get("minecraft:leather_chestplate"); @Nullable public static final ItemType LEATHER_HELMET = get("minecraft:leather_helmet"); + @Nullable public static final ItemType LEATHER_HORSE_ARMOR = get("minecraft:leather_horse_armor"); @Nullable public static final ItemType LEATHER_LEGGINGS = get("minecraft:leather_leggings"); + @Nullable public static final ItemType LECTERN = get("minecraft:lectern"); @Nullable public static final ItemType LEVER = get("minecraft:lever"); @Nullable public static final ItemType LIGHT_BLUE_BANNER = get("minecraft:light_blue_banner"); @Nullable public static final ItemType LIGHT_BLUE_BED = get("minecraft:light_blue_bed"); @@ -452,6 +496,7 @@ public final class ItemTypes { @Nullable public static final ItemType LIGHT_GRAY_WOOL = get("minecraft:light_gray_wool"); @Nullable public static final ItemType LIGHT_WEIGHTED_PRESSURE_PLATE = get("minecraft:light_weighted_pressure_plate"); @Nullable public static final ItemType LILAC = get("minecraft:lilac"); + @Nullable public static final ItemType LILY_OF_THE_VALLEY = get("minecraft:lily_of_the_valley"); @Nullable public static final ItemType LILY_PAD = get("minecraft:lily_pad"); @Nullable public static final ItemType LIME_BANNER = get("minecraft:lime_banner"); @Nullable public static final ItemType LIME_BED = get("minecraft:lime_bed"); @@ -467,6 +512,7 @@ public final class ItemTypes { @Nullable public static final ItemType LIME_WOOL = get("minecraft:lime_wool"); @Nullable public static final ItemType LINGERING_POTION = get("minecraft:lingering_potion"); @Nullable public static final ItemType LLAMA_SPAWN_EGG = get("minecraft:llama_spawn_egg"); + @Nullable public static final ItemType LOOM = get("minecraft:loom"); @Nullable public static final ItemType MAGENTA_BANNER = get("minecraft:magenta_banner"); @Nullable public static final ItemType MAGENTA_BED = get("minecraft:magenta_bed"); @Nullable public static final ItemType MAGENTA_CARPET = get("minecraft:magenta_carpet"); @@ -488,9 +534,15 @@ public final class ItemTypes { @Nullable public static final ItemType MELON_SLICE = get("minecraft:melon_slice"); @Nullable public static final ItemType MILK_BUCKET = get("minecraft:milk_bucket"); @Nullable public static final ItemType MINECART = get("minecraft:minecart"); + @Nullable public static final ItemType MOJANG_BANNER_PATTERN = get("minecraft:mojang_banner_pattern"); @Nullable public static final ItemType MOOSHROOM_SPAWN_EGG = get("minecraft:mooshroom_spawn_egg"); @Nullable public static final ItemType MOSSY_COBBLESTONE = get("minecraft:mossy_cobblestone"); + @Nullable public static final ItemType MOSSY_COBBLESTONE_SLAB = get("minecraft:mossy_cobblestone_slab"); + @Nullable public static final ItemType MOSSY_COBBLESTONE_STAIRS = get("minecraft:mossy_cobblestone_stairs"); @Nullable public static final ItemType MOSSY_COBBLESTONE_WALL = get("minecraft:mossy_cobblestone_wall"); + @Nullable public static final ItemType MOSSY_STONE_BRICK_SLAB = get("minecraft:mossy_stone_brick_slab"); + @Nullable public static final ItemType MOSSY_STONE_BRICK_STAIRS = get("minecraft:mossy_stone_brick_stairs"); + @Nullable public static final ItemType MOSSY_STONE_BRICK_WALL = get("minecraft:mossy_stone_brick_wall"); @Nullable public static final ItemType MOSSY_STONE_BRICKS = get("minecraft:mossy_stone_bricks"); @Nullable public static final ItemType MULE_SPAWN_EGG = get("minecraft:mule_spawn_egg"); @Nullable public static final ItemType MUSHROOM_STEM = get("minecraft:mushroom_stem"); @@ -515,6 +567,7 @@ public final class ItemTypes { @Nullable public static final ItemType NETHER_BRICK_FENCE = get("minecraft:nether_brick_fence"); @Nullable public static final ItemType NETHER_BRICK_SLAB = get("minecraft:nether_brick_slab"); @Nullable public static final ItemType NETHER_BRICK_STAIRS = get("minecraft:nether_brick_stairs"); + @Nullable public static final ItemType NETHER_BRICK_WALL = get("minecraft:nether_brick_wall"); @Nullable public static final ItemType NETHER_BRICKS = get("minecraft:nether_bricks"); @Nullable public static final ItemType NETHER_QUARTZ_ORE = get("minecraft:nether_quartz_ore"); @Nullable public static final ItemType NETHER_STAR = get("minecraft:nether_star"); @@ -532,6 +585,7 @@ public final class ItemTypes { @Nullable public static final ItemType OAK_PLANKS = get("minecraft:oak_planks"); @Nullable public static final ItemType OAK_PRESSURE_PLATE = get("minecraft:oak_pressure_plate"); @Nullable public static final ItemType OAK_SAPLING = get("minecraft:oak_sapling"); + @Nullable public static final ItemType OAK_SIGN = get("minecraft:oak_sign"); @Nullable public static final ItemType OAK_SLAB = get("minecraft:oak_slab"); @Nullable public static final ItemType OAK_STAIRS = get("minecraft:oak_stairs"); @Nullable public static final ItemType OAK_TRAPDOOR = get("minecraft:oak_trapdoor"); @@ -555,6 +609,7 @@ public final class ItemTypes { @Nullable public static final ItemType OXEYE_DAISY = get("minecraft:oxeye_daisy"); @Nullable public static final ItemType PACKED_ICE = get("minecraft:packed_ice"); @Nullable public static final ItemType PAINTING = get("minecraft:painting"); + @Nullable public static final ItemType PANDA_SPAWN_EGG = get("minecraft:panda_spawn_egg"); @Nullable public static final ItemType PAPER = get("minecraft:paper"); @Nullable public static final ItemType PARROT_SPAWN_EGG = get("minecraft:parrot_spawn_egg"); @Nullable public static final ItemType PEONY = get("minecraft:peony"); @@ -562,6 +617,7 @@ public final class ItemTypes { @Nullable public static final ItemType PHANTOM_MEMBRANE = get("minecraft:phantom_membrane"); @Nullable public static final ItemType PHANTOM_SPAWN_EGG = get("minecraft:phantom_spawn_egg"); @Nullable public static final ItemType PIG_SPAWN_EGG = get("minecraft:pig_spawn_egg"); + @Nullable public static final ItemType PILLAGER_SPAWN_EGG = get("minecraft:pillager_spawn_egg"); @Nullable public static final ItemType PINK_BANNER = get("minecraft:pink_banner"); @Nullable public static final ItemType PINK_BED = get("minecraft:pink_bed"); @Nullable public static final ItemType PINK_CARPET = get("minecraft:pink_carpet"); @@ -581,8 +637,14 @@ public final class ItemTypes { @Nullable public static final ItemType POISONOUS_POTATO = get("minecraft:poisonous_potato"); @Nullable public static final ItemType POLAR_BEAR_SPAWN_EGG = get("minecraft:polar_bear_spawn_egg"); @Nullable public static final ItemType POLISHED_ANDESITE = get("minecraft:polished_andesite"); + @Nullable public static final ItemType POLISHED_ANDESITE_SLAB = get("minecraft:polished_andesite_slab"); + @Nullable public static final ItemType POLISHED_ANDESITE_STAIRS = get("minecraft:polished_andesite_stairs"); @Nullable public static final ItemType POLISHED_DIORITE = get("minecraft:polished_diorite"); + @Nullable public static final ItemType POLISHED_DIORITE_SLAB = get("minecraft:polished_diorite_slab"); + @Nullable public static final ItemType POLISHED_DIORITE_STAIRS = get("minecraft:polished_diorite_stairs"); @Nullable public static final ItemType POLISHED_GRANITE = get("minecraft:polished_granite"); + @Nullable public static final ItemType POLISHED_GRANITE_SLAB = get("minecraft:polished_granite_slab"); + @Nullable public static final ItemType POLISHED_GRANITE_STAIRS = get("minecraft:polished_granite_stairs"); @Nullable public static final ItemType POPPED_CHORUS_FRUIT = get("minecraft:popped_chorus_fruit"); @Nullable public static final ItemType POPPY = get("minecraft:poppy"); @Nullable public static final ItemType PORKCHOP = get("minecraft:porkchop"); @@ -597,6 +659,7 @@ public final class ItemTypes { @Nullable public static final ItemType PRISMARINE_SHARD = get("minecraft:prismarine_shard"); @Nullable public static final ItemType PRISMARINE_SLAB = get("minecraft:prismarine_slab"); @Nullable public static final ItemType PRISMARINE_STAIRS = get("minecraft:prismarine_stairs"); + @Nullable public static final ItemType PRISMARINE_WALL = get("minecraft:prismarine_wall"); @Nullable public static final ItemType PUFFERFISH = get("minecraft:pufferfish"); @Nullable public static final ItemType PUFFERFISH_BUCKET = get("minecraft:pufferfish_bucket"); @Nullable public static final ItemType PUFFERFISH_SPAWN_EGG = get("minecraft:pufferfish_spawn_egg"); @@ -630,19 +693,25 @@ public final class ItemTypes { @Nullable public static final ItemType RABBIT_SPAWN_EGG = get("minecraft:rabbit_spawn_egg"); @Nullable public static final ItemType RABBIT_STEW = get("minecraft:rabbit_stew"); @Nullable public static final ItemType RAIL = get("minecraft:rail"); + @Nullable public static final ItemType RAVAGER_SPAWN_EGG = get("minecraft:ravager_spawn_egg"); @Nullable public static final ItemType RED_BANNER = get("minecraft:red_banner"); @Nullable public static final ItemType RED_BED = get("minecraft:red_bed"); @Nullable public static final ItemType RED_CARPET = get("minecraft:red_carpet"); @Nullable public static final ItemType RED_CONCRETE = get("minecraft:red_concrete"); @Nullable public static final ItemType RED_CONCRETE_POWDER = get("minecraft:red_concrete_powder"); + @Nullable public static final ItemType RED_DYE = get("minecraft:red_dye"); @Nullable public static final ItemType RED_GLAZED_TERRACOTTA = get("minecraft:red_glazed_terracotta"); @Nullable public static final ItemType RED_MUSHROOM = get("minecraft:red_mushroom"); @Nullable public static final ItemType RED_MUSHROOM_BLOCK = get("minecraft:red_mushroom_block"); + @Nullable public static final ItemType RED_NETHER_BRICK_SLAB = get("minecraft:red_nether_brick_slab"); + @Nullable public static final ItemType RED_NETHER_BRICK_STAIRS = get("minecraft:red_nether_brick_stairs"); + @Nullable public static final ItemType RED_NETHER_BRICK_WALL = get("minecraft:red_nether_brick_wall"); @Nullable public static final ItemType RED_NETHER_BRICKS = get("minecraft:red_nether_bricks"); @Nullable public static final ItemType RED_SAND = get("minecraft:red_sand"); @Nullable public static final ItemType RED_SANDSTONE = get("minecraft:red_sandstone"); @Nullable public static final ItemType RED_SANDSTONE_SLAB = get("minecraft:red_sandstone_slab"); @Nullable public static final ItemType RED_SANDSTONE_STAIRS = get("minecraft:red_sandstone_stairs"); + @Nullable public static final ItemType RED_SANDSTONE_WALL = get("minecraft:red_sandstone_wall"); @Nullable public static final ItemType RED_SHULKER_BOX = get("minecraft:red_shulker_box"); @Nullable public static final ItemType RED_STAINED_GLASS = get("minecraft:red_stained_glass"); @Nullable public static final ItemType RED_STAINED_GLASS_PANE = get("minecraft:red_stained_glass_pane"); @@ -657,7 +726,7 @@ public final class ItemTypes { @Nullable public static final ItemType REPEATER = get("minecraft:repeater"); @Nullable public static final ItemType REPEATING_COMMAND_BLOCK = get("minecraft:repeating_command_block"); @Nullable public static final ItemType ROSE_BUSH = get("minecraft:rose_bush"); - @Nullable public static final ItemType ROSE_RED = get("minecraft:rose_red"); + @Deprecated @Nullable public static final ItemType ROSE_RED = Optional.ofNullable(get("minecraft:rose_red")).orElseGet(() -> (get("minecraft:red_dye"))); @Nullable public static final ItemType ROTTEN_FLESH = get("minecraft:rotten_flesh"); @Nullable public static final ItemType SADDLE = get("minecraft:saddle"); @Nullable public static final ItemType SALMON = get("minecraft:salmon"); @@ -667,6 +736,8 @@ public final class ItemTypes { @Nullable public static final ItemType SANDSTONE = get("minecraft:sandstone"); @Nullable public static final ItemType SANDSTONE_SLAB = get("minecraft:sandstone_slab"); @Nullable public static final ItemType SANDSTONE_STAIRS = get("minecraft:sandstone_stairs"); + @Nullable public static final ItemType SANDSTONE_WALL = get("minecraft:sandstone_wall"); + @Nullable public static final ItemType SCAFFOLDING = get("minecraft:scaffolding"); @Nullable public static final ItemType SCUTE = get("minecraft:scute"); @Nullable public static final ItemType SEA_LANTERN = get("minecraft:sea_lantern"); @Nullable public static final ItemType SEA_PICKLE = get("minecraft:sea_pickle"); @@ -677,18 +748,28 @@ public final class ItemTypes { @Nullable public static final ItemType SHULKER_BOX = get("minecraft:shulker_box"); @Nullable public static final ItemType SHULKER_SHELL = get("minecraft:shulker_shell"); @Nullable public static final ItemType SHULKER_SPAWN_EGG = get("minecraft:shulker_spawn_egg"); - @Nullable public static final ItemType SIGN = get("minecraft:sign"); + @Deprecated @Nullable public static final ItemType SIGN = Optional.ofNullable(get("minecraft:sign")).orElseGet(() -> (get("minecraft:oak_sign"))); @Nullable public static final ItemType SILVERFISH_SPAWN_EGG = get("minecraft:silverfish_spawn_egg"); @Nullable public static final ItemType SKELETON_HORSE_SPAWN_EGG = get("minecraft:skeleton_horse_spawn_egg"); @Nullable public static final ItemType SKELETON_SKULL = get("minecraft:skeleton_skull"); @Nullable public static final ItemType SKELETON_SPAWN_EGG = get("minecraft:skeleton_spawn_egg"); + @Nullable public static final ItemType SKULL_BANNER_PATTERN = get("minecraft:skull_banner_pattern"); @Nullable public static final ItemType SLIME_BALL = get("minecraft:slime_ball"); @Nullable public static final ItemType SLIME_BLOCK = get("minecraft:slime_block"); @Nullable public static final ItemType SLIME_SPAWN_EGG = get("minecraft:slime_spawn_egg"); + @Nullable public static final ItemType SMITHING_TABLE = get("minecraft:smithing_table"); + @Nullable public static final ItemType SMOKER = get("minecraft:smoker"); @Nullable public static final ItemType SMOOTH_QUARTZ = get("minecraft:smooth_quartz"); + @Nullable public static final ItemType SMOOTH_QUARTZ_SLAB = get("minecraft:smooth_quartz_slab"); + @Nullable public static final ItemType SMOOTH_QUARTZ_STAIRS = get("minecraft:smooth_quartz_stairs"); @Nullable public static final ItemType SMOOTH_RED_SANDSTONE = get("minecraft:smooth_red_sandstone"); + @Nullable public static final ItemType SMOOTH_RED_SANDSTONE_SLAB = get("minecraft:smooth_red_sandstone_slab"); + @Nullable public static final ItemType SMOOTH_RED_SANDSTONE_STAIRS = get("minecraft:smooth_red_sandstone_stairs"); @Nullable public static final ItemType SMOOTH_SANDSTONE = get("minecraft:smooth_sandstone"); + @Nullable public static final ItemType SMOOTH_SANDSTONE_SLAB = get("minecraft:smooth_sandstone_slab"); + @Nullable public static final ItemType SMOOTH_SANDSTONE_STAIRS = get("minecraft:smooth_sandstone_stairs"); @Nullable public static final ItemType SMOOTH_STONE = get("minecraft:smooth_stone"); + @Nullable public static final ItemType SMOOTH_STONE_SLAB = get("minecraft:smooth_stone_slab"); @Nullable public static final ItemType SNOW = get("minecraft:snow"); @Nullable public static final ItemType SNOW_BLOCK = get("minecraft:snow_block"); @Nullable public static final ItemType SNOWBALL = get("minecraft:snowball"); @@ -709,6 +790,7 @@ public final class ItemTypes { @Nullable public static final ItemType SPRUCE_PLANKS = get("minecraft:spruce_planks"); @Nullable public static final ItemType SPRUCE_PRESSURE_PLATE = get("minecraft:spruce_pressure_plate"); @Nullable public static final ItemType SPRUCE_SAPLING = get("minecraft:spruce_sapling"); + @Nullable public static final ItemType SPRUCE_SIGN = get("minecraft:spruce_sign"); @Nullable public static final ItemType SPRUCE_SLAB = get("minecraft:spruce_slab"); @Nullable public static final ItemType SPRUCE_STAIRS = get("minecraft:spruce_stairs"); @Nullable public static final ItemType SPRUCE_TRAPDOOR = get("minecraft:spruce_trapdoor"); @@ -720,6 +802,7 @@ public final class ItemTypes { @Nullable public static final ItemType STONE_AXE = get("minecraft:stone_axe"); @Nullable public static final ItemType STONE_BRICK_SLAB = get("minecraft:stone_brick_slab"); @Nullable public static final ItemType STONE_BRICK_STAIRS = get("minecraft:stone_brick_stairs"); + @Nullable public static final ItemType STONE_BRICK_WALL = get("minecraft:stone_brick_wall"); @Nullable public static final ItemType STONE_BRICKS = get("minecraft:stone_bricks"); @Nullable public static final ItemType STONE_BUTTON = get("minecraft:stone_button"); @Nullable public static final ItemType STONE_HOE = get("minecraft:stone_hoe"); @@ -727,7 +810,9 @@ public final class ItemTypes { @Nullable public static final ItemType STONE_PRESSURE_PLATE = get("minecraft:stone_pressure_plate"); @Nullable public static final ItemType STONE_SHOVEL = get("minecraft:stone_shovel"); @Nullable public static final ItemType STONE_SLAB = get("minecraft:stone_slab"); + @Nullable public static final ItemType STONE_STAIRS = get("minecraft:stone_stairs"); @Nullable public static final ItemType STONE_SWORD = get("minecraft:stone_sword"); + @Nullable public static final ItemType STONECUTTER = get("minecraft:stonecutter"); @Nullable public static final ItemType STRAY_SPAWN_EGG = get("minecraft:stray_spawn_egg"); @Nullable public static final ItemType STRING = get("minecraft:string"); @Nullable public static final ItemType STRIPPED_ACACIA_LOG = get("minecraft:stripped_acacia_log"); @@ -747,6 +832,8 @@ public final class ItemTypes { @Nullable public static final ItemType SUGAR = get("minecraft:sugar"); @Nullable public static final ItemType SUGAR_CANE = get("minecraft:sugar_cane"); @Nullable public static final ItemType SUNFLOWER = get("minecraft:sunflower"); + @Nullable public static final ItemType SUSPICIOUS_STEW = get("minecraft:suspicious_stew"); + @Nullable public static final ItemType SWEET_BERRIES = get("minecraft:sweet_berries"); @Nullable public static final ItemType TALL_GRASS = get("minecraft:tall_grass"); @Nullable public static final ItemType TERRACOTTA = get("minecraft:terracotta"); @Nullable public static final ItemType TIPPED_ARROW = get("minecraft:tipped_arrow"); @@ -754,6 +841,7 @@ public final class ItemTypes { @Nullable public static final ItemType TNT_MINECART = get("minecraft:tnt_minecart"); @Nullable public static final ItemType TORCH = get("minecraft:torch"); @Nullable public static final ItemType TOTEM_OF_UNDYING = get("minecraft:totem_of_undying"); + @Nullable public static final ItemType TRADER_LLAMA_SPAWN_EGG = get("minecraft:trader_llama_spawn_egg"); @Nullable public static final ItemType TRAPPED_CHEST = get("minecraft:trapped_chest"); @Nullable public static final ItemType TRIDENT = get("minecraft:trident"); @Nullable public static final ItemType TRIPWIRE_HOOK = get("minecraft:tripwire_hook"); @@ -770,6 +858,7 @@ public final class ItemTypes { @Nullable public static final ItemType VILLAGER_SPAWN_EGG = get("minecraft:villager_spawn_egg"); @Nullable public static final ItemType VINDICATOR_SPAWN_EGG = get("minecraft:vindicator_spawn_egg"); @Nullable public static final ItemType VINE = get("minecraft:vine"); + @Nullable public static final ItemType WANDERING_TRADER_SPAWN_EGG = get("minecraft:wandering_trader_spawn_egg"); @Nullable public static final ItemType WATER_BUCKET = get("minecraft:water_bucket"); @Nullable public static final ItemType WET_SPONGE = get("minecraft:wet_sponge"); @Nullable public static final ItemType WHEAT = get("minecraft:wheat"); @@ -779,6 +868,7 @@ public final class ItemTypes { @Nullable public static final ItemType WHITE_CARPET = get("minecraft:white_carpet"); @Nullable public static final ItemType WHITE_CONCRETE = get("minecraft:white_concrete"); @Nullable public static final ItemType WHITE_CONCRETE_POWDER = get("minecraft:white_concrete_powder"); + @Nullable public static final ItemType WHITE_DYE = get("minecraft:white_dye"); @Nullable public static final ItemType WHITE_GLAZED_TERRACOTTA = get("minecraft:white_glazed_terracotta"); @Nullable public static final ItemType WHITE_SHULKER_BOX = get("minecraft:white_shulker_box"); @Nullable public static final ItemType WHITE_STAINED_GLASS = get("minecraft:white_stained_glass"); @@ -787,6 +877,7 @@ public final class ItemTypes { @Nullable public static final ItemType WHITE_TULIP = get("minecraft:white_tulip"); @Nullable public static final ItemType WHITE_WOOL = get("minecraft:white_wool"); @Nullable public static final ItemType WITCH_SPAWN_EGG = get("minecraft:witch_spawn_egg"); + @Nullable public static final ItemType WITHER_ROSE = get("minecraft:wither_rose"); @Nullable public static final ItemType WITHER_SKELETON_SKULL = get("minecraft:wither_skeleton_skull"); @Nullable public static final ItemType WITHER_SKELETON_SPAWN_EGG = get("minecraft:wither_skeleton_spawn_egg"); @Nullable public static final ItemType WOLF_SPAWN_EGG = get("minecraft:wolf_spawn_egg"); @@ -802,6 +893,7 @@ public final class ItemTypes { @Nullable public static final ItemType YELLOW_CARPET = get("minecraft:yellow_carpet"); @Nullable public static final ItemType YELLOW_CONCRETE = get("minecraft:yellow_concrete"); @Nullable public static final ItemType YELLOW_CONCRETE_POWDER = get("minecraft:yellow_concrete_powder"); + @Nullable public static final ItemType YELLOW_DYE = get("minecraft:yellow_dye"); @Nullable public static final ItemType YELLOW_GLAZED_TERRACOTTA = get("minecraft:yellow_glazed_terracotta"); @Nullable public static final ItemType YELLOW_SHULKER_BOX = get("minecraft:yellow_shulker_box"); @Nullable public static final ItemType YELLOW_STAINED_GLASS = get("minecraft:yellow_stained_glass"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java index 76cd902ef..59505f2f4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledBlockData.java @@ -23,6 +23,8 @@ import com.google.common.io.Resources; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.gson.VectorAdapter; import com.sk89q.worldedit.util.io.ResourceLoader; @@ -48,7 +50,7 @@ import java.util.Map; * reading fails (which occurs when this class is first instantiated), then * the methods will return {@code null}s for all blocks.

    */ -public class BundledBlockData { +public final class BundledBlockData { private static final Logger log = LoggerFactory.getLogger(BundledBlockData.class); private static BundledBlockData INSTANCE; @@ -75,10 +77,18 @@ public class BundledBlockData { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); Gson gson = gsonBuilder.create(); - URL url = ResourceLoader.getResource(BundledBlockData.class, "blocks.json"); + URL url = null; + final int dataVersion = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion(); + if (dataVersion > 1900) { // > MC 1.13 + url = ResourceLoader.getResource(BundledBlockData.class, "blocks.114.json"); + } + if (url == null) { + url = ResourceLoader.getResource(BundledBlockData.class, "blocks.json"); + } if (url == null) { throw new IOException("Could not find blocks.json"); } + log.debug("Using {} for bundled block data.", url); String data = Resources.toString(url, Charset.defaultCharset()); List entries = gson.fromJson(data, new TypeToken>() {}.getType()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java index 4e1af0422..28c6c6aa7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BundledItemData.java @@ -23,6 +23,8 @@ import com.google.common.io.Resources; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.gson.VectorAdapter; import com.sk89q.worldedit.util.io.ResourceLoader; @@ -48,7 +50,7 @@ import java.util.Map; * reading fails (which occurs when this class is first instantiated), then * the methods will return {@code null}s for all items.

    */ -public class BundledItemData { +public final class BundledItemData { private static final Logger log = LoggerFactory.getLogger(BundledItemData.class); private static BundledItemData INSTANCE; @@ -75,10 +77,18 @@ public class BundledItemData { GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Vector3.class, new VectorAdapter()); Gson gson = gsonBuilder.create(); - URL url = ResourceLoader.getResource(BundledItemData.class,"items.json"); + URL url = null; + final int dataVersion = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getDataVersion(); + if (dataVersion > 1900) { // > MC 1.13 + url = ResourceLoader.getResource(BundledBlockData.class, "items.114.json"); + } + if (url == null) { + url = ResourceLoader.getResource(BundledBlockData.class, "items.json"); + } if (url == null) { throw new IOException("Could not find items.json"); } + log.debug("Using {} for bundled item data.", url); String data = Resources.toString(url, Charset.defaultCharset()); List entries = gson.fromJson(data, new TypeToken>() {}.getType()); diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.114.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.114.json new file mode 100644 index 000000000..d5f98648d --- /dev/null +++ b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.114.json @@ -0,0 +1,16902 @@ +[ + { + "id": "minecraft:acacia_button", + "localizedName": "Acacia Button", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_door", + "localizedName": "Acacia Door", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_fence", + "localizedName": "Acacia Fence", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_fence_gate", + "localizedName": "Acacia Fence Gate", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_leaves", + "localizedName": "Acacia Leaves", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_log", + "localizedName": "Acacia Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_planks", + "localizedName": "Acacia Planks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_pressure_plate", + "localizedName": "Acacia Pressure Plate", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_sapling", + "localizedName": "Acacia Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_sign", + "localizedName": "Acacia Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_slab", + "localizedName": "Acacia Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_stairs", + "localizedName": "Acacia Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_trapdoor", + "localizedName": "Acacia Trapdoor", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_wall_sign", + "localizedName": "Acacia Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:acacia_wood", + "localizedName": "Acacia Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:activator_rail", + "localizedName": "Activator Rail", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.7, + "resistance": 0.7, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:air", + "localizedName": "Air", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:allium", + "localizedName": "Allium", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:andesite", + "localizedName": "Andesite", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:andesite_slab", + "localizedName": "Andesite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:andesite_stairs", + "localizedName": "Andesite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:andesite_wall", + "localizedName": "Andesite Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:anvil", + "localizedName": "Anvil", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 1200.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:attached_melon_stem", + "localizedName": "Attached Melon Stem", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:attached_pumpkin_stem", + "localizedName": "Attached Pumpkin Stem", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:azure_bluet", + "localizedName": "Azure Bluet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bamboo", + "localizedName": "Bamboo", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bamboo_sapling", + "localizedName": "Bamboo Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": false, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:barrel", + "localizedName": "Barrel", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:barrier", + "localizedName": "Barrier", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": -1.0, + "resistance": 3600000.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:beacon", + "localizedName": "Beacon", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bedrock", + "localizedName": "Bedrock", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": -1.0, + "resistance": 3600000.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:beetroots", + "localizedName": "Beetroots", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bell", + "localizedName": "Bell", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 5.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_button", + "localizedName": "Birch Button", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_door", + "localizedName": "Birch Door", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_fence", + "localizedName": "Birch Fence", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_fence_gate", + "localizedName": "Birch Fence Gate", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_leaves", + "localizedName": "Birch Leaves", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_log", + "localizedName": "Birch Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_planks", + "localizedName": "Birch Planks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_pressure_plate", + "localizedName": "Birch Pressure Plate", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_sapling", + "localizedName": "Birch Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_sign", + "localizedName": "Birch Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_slab", + "localizedName": "Birch Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_stairs", + "localizedName": "Birch Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_trapdoor", + "localizedName": "Birch Trapdoor", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_wall_sign", + "localizedName": "Birch Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:birch_wood", + "localizedName": "Birch Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_banner", + "localizedName": "Black Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_bed", + "localizedName": "Black Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_carpet", + "localizedName": "Black Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_concrete", + "localizedName": "Black Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_concrete_powder", + "localizedName": "Black Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_glazed_terracotta", + "localizedName": "Black Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_shulker_box", + "localizedName": "Black Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:black_stained_glass", + "localizedName": "Black Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_stained_glass_pane", + "localizedName": "Black Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_terracotta", + "localizedName": "Black Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_wall_banner", + "localizedName": "Black Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:black_wool", + "localizedName": "Black Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blast_furnace", + "localizedName": "Blast Furnace", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:blue_banner", + "localizedName": "Blue Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_bed", + "localizedName": "Blue Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_carpet", + "localizedName": "Blue Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_concrete", + "localizedName": "Blue Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_concrete_powder", + "localizedName": "Blue Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_glazed_terracotta", + "localizedName": "Blue Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_ice", + "localizedName": "Blue Ice", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.8, + "resistance": 2.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.989, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a0a0ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_orchid", + "localizedName": "Blue Orchid", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_shulker_box", + "localizedName": "Blue Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:blue_stained_glass", + "localizedName": "Blue Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_stained_glass_pane", + "localizedName": "Blue Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_terracotta", + "localizedName": "Blue Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_wall_banner", + "localizedName": "Blue Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:blue_wool", + "localizedName": "Blue Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bone_block", + "localizedName": "Bone Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bookshelf", + "localizedName": "Bookshelf", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 1.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brain_coral", + "localizedName": "Brain Coral", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brain_coral_block", + "localizedName": "Brain Coral Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brain_coral_fan", + "localizedName": "Brain Coral Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brain_coral_wall_fan", + "localizedName": "Brain Coral Wall Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brewing_stand", + "localizedName": "Brewing Stand", + "material": { + "powerSource": false, + "lightValue": 1, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:brick_slab", + "localizedName": "Brick Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brick_stairs", + "localizedName": "Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brick_wall", + "localizedName": "Brick Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bricks", + "localizedName": "Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_banner", + "localizedName": "Brown Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_bed", + "localizedName": "Brown Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_carpet", + "localizedName": "Brown Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_concrete", + "localizedName": "Brown Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_concrete_powder", + "localizedName": "Brown Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_glazed_terracotta", + "localizedName": "Brown Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_mushroom", + "localizedName": "Brown Mushroom", + "material": { + "powerSource": false, + "lightValue": 1, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_mushroom_block", + "localizedName": "Brown Mushroom Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_shulker_box", + "localizedName": "Brown Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:brown_stained_glass", + "localizedName": "Brown Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_stained_glass_pane", + "localizedName": "Brown Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_terracotta", + "localizedName": "Brown Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_wall_banner", + "localizedName": "Brown Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:brown_wool", + "localizedName": "Brown Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bubble_column", + "localizedName": "Bubble Column", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": true, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bubble_coral", + "localizedName": "Bubble Coral", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bubble_coral_block", + "localizedName": "Bubble Coral Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bubble_coral_fan", + "localizedName": "Bubble Coral Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:bubble_coral_wall_fan", + "localizedName": "Bubble Coral Wall Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cactus", + "localizedName": "Cactus", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.4, + "resistance": 0.4, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cake", + "localizedName": "Cake", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:campfire", + "localizedName": "Campfire", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:carrots", + "localizedName": "Carrots", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cartography_table", + "localizedName": "Cartography Table", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:carved_pumpkin", + "localizedName": "Carved Pumpkin", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cauldron", + "localizedName": "Cauldron", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cave_air", + "localizedName": "Cave Air", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:chain_command_block", + "localizedName": "Chain Command Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": -1.0, + "resistance": 3600000.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:chest", + "localizedName": "Chest", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:chipped_anvil", + "localizedName": "Chipped Anvil", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 1200.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:chiseled_quartz_block", + "localizedName": "Chiseled Quartz Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:chiseled_red_sandstone", + "localizedName": "Chiseled Red Sandstone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:chiseled_sandstone", + "localizedName": "Chiseled Sandstone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:chiseled_stone_bricks", + "localizedName": "Chiseled Stone Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:chorus_flower", + "localizedName": "Chorus Flower", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.4, + "resistance": 0.4, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:chorus_plant", + "localizedName": "Chorus Plant", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.4, + "resistance": 0.4, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:clay", + "localizedName": "Clay", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.6, + "resistance": 0.6, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a4a8b8", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:coal_block", + "localizedName": "Block of Coal", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:coal_ore", + "localizedName": "Coal Ore", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:coarse_dirt", + "localizedName": "Coarse Dirt", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#976d4d", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cobblestone", + "localizedName": "Cobblestone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cobblestone_slab", + "localizedName": "Cobblestone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cobblestone_stairs", + "localizedName": "Cobblestone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cobblestone_wall", + "localizedName": "Cobblestone Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cobweb", + "localizedName": "Cobweb", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 4.0, + "resistance": 4.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cocoa", + "localizedName": "Cocoa", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 3.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:command_block", + "localizedName": "Command Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": -1.0, + "resistance": 3600000.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:comparator", + "localizedName": "Redstone Comparator", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:composter", + "localizedName": "Composter", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.6, + "resistance": 0.6, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:conduit", + "localizedName": "Conduit", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cornflower", + "localizedName": "Cornflower", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cracked_stone_bricks", + "localizedName": "Cracked Stone Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:crafting_table", + "localizedName": "Crafting Table", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:creeper_head", + "localizedName": "Creeper Head", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:creeper_wall_head", + "localizedName": "Creeper Head", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cut_red_sandstone", + "localizedName": "Cut Red Sandstone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cut_red_sandstone_slab", + "localizedName": "Cut Red Sandstone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cut_sandstone", + "localizedName": "Cut Sandstone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cut_sandstone_slab", + "localizedName": "Cut Sandstone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_banner", + "localizedName": "Cyan Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_bed", + "localizedName": "Cyan Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_carpet", + "localizedName": "Cyan Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_concrete", + "localizedName": "Cyan Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_concrete_powder", + "localizedName": "Cyan Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_glazed_terracotta", + "localizedName": "Cyan Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_shulker_box", + "localizedName": "Cyan Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:cyan_stained_glass", + "localizedName": "Cyan Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_stained_glass_pane", + "localizedName": "Cyan Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_terracotta", + "localizedName": "Cyan Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_wall_banner", + "localizedName": "Cyan Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:cyan_wool", + "localizedName": "Cyan Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:damaged_anvil", + "localizedName": "Damaged Anvil", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 1200.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dandelion", + "localizedName": "Dandelion", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_button", + "localizedName": "Dark Oak Button", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_door", + "localizedName": "Dark Oak Door", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_fence", + "localizedName": "Dark Oak Fence", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_fence_gate", + "localizedName": "Dark Oak Fence Gate", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_leaves", + "localizedName": "Dark Oak Leaves", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_log", + "localizedName": "Dark Oak Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_planks", + "localizedName": "Dark Oak Planks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_pressure_plate", + "localizedName": "Dark Oak Pressure Plate", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_sapling", + "localizedName": "Dark Oak Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_sign", + "localizedName": "Dark Oak Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_slab", + "localizedName": "Dark Oak Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_stairs", + "localizedName": "Dark Oak Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_trapdoor", + "localizedName": "Dark Oak Trapdoor", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_wall_sign", + "localizedName": "Dark Oak Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_oak_wood", + "localizedName": "Dark Oak Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_prismarine", + "localizedName": "Dark Prismarine", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_prismarine_slab", + "localizedName": "Dark Prismarine Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dark_prismarine_stairs", + "localizedName": "Dark Prismarine Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:daylight_detector", + "localizedName": "Daylight Detector", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_brain_coral", + "localizedName": "Dead Brain Coral", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_brain_coral_block", + "localizedName": "Dead Brain Coral Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_brain_coral_fan", + "localizedName": "Dead Brain Coral Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_brain_coral_wall_fan", + "localizedName": "Dead Brain Coral Wall Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_bubble_coral", + "localizedName": "Dead Bubble Coral", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_bubble_coral_block", + "localizedName": "Dead Bubble Coral Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_bubble_coral_fan", + "localizedName": "Dead Bubble Coral Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_bubble_coral_wall_fan", + "localizedName": "Dead Bubble Coral Wall Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_bush", + "localizedName": "Dead Bush", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_fire_coral", + "localizedName": "Dead Fire Coral", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_fire_coral_block", + "localizedName": "Dead Fire Coral Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_fire_coral_fan", + "localizedName": "Dead Fire Coral Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_fire_coral_wall_fan", + "localizedName": "Dead Fire Coral Wall Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_horn_coral", + "localizedName": "Dead Horn Coral", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_horn_coral_block", + "localizedName": "Dead Horn Coral Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_horn_coral_fan", + "localizedName": "Dead Horn Coral Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_horn_coral_wall_fan", + "localizedName": "Dead Horn Coral Wall Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_tube_coral", + "localizedName": "Dead Tube Coral", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_tube_coral_block", + "localizedName": "Dead Tube Coral Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_tube_coral_fan", + "localizedName": "Dead Tube Coral Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dead_tube_coral_wall_fan", + "localizedName": "Dead Tube Coral Wall Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:detector_rail", + "localizedName": "Detector Rail", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.7, + "resistance": 0.7, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:diamond_block", + "localizedName": "Block of Diamond", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:diamond_ore", + "localizedName": "Diamond Ore", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:diorite", + "localizedName": "Diorite", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:diorite_slab", + "localizedName": "Diorite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:diorite_stairs", + "localizedName": "Diorite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:diorite_wall", + "localizedName": "Diorite Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dirt", + "localizedName": "Dirt", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#976d4d", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dispenser", + "localizedName": "Dispenser", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:dragon_egg", + "localizedName": "Dragon Egg", + "material": { + "powerSource": false, + "lightValue": 1, + "hardness": 3.0, + "resistance": 9.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dragon_head", + "localizedName": "Dragon Head", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dragon_wall_head", + "localizedName": "Dragon Head", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dried_kelp_block", + "localizedName": "Dried Kelp Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7fb238", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:dropper", + "localizedName": "Dropper", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:emerald_block", + "localizedName": "Block of Emerald", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:emerald_ore", + "localizedName": "Emerald Ore", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:enchanting_table", + "localizedName": "Enchanting Table", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 1200.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_gateway", + "localizedName": "End Gateway", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": -1.0, + "resistance": 3600000.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_portal", + "localizedName": "End Portal", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": -1.0, + "resistance": 3600000.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_portal_frame", + "localizedName": "End Portal Frame", + "material": { + "powerSource": false, + "lightValue": 1, + "hardness": -1.0, + "resistance": 3600000.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_rod", + "localizedName": "End Rod", + "material": { + "powerSource": false, + "lightValue": 14, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_stone", + "localizedName": "End Stone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 9.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_stone_brick_slab", + "localizedName": "End Stone Brick Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_stone_brick_stairs", + "localizedName": "End Stone Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_stone_brick_wall", + "localizedName": "End Stone Brick Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:end_stone_bricks", + "localizedName": "End Stone Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:ender_chest", + "localizedName": "Ender Chest", + "material": { + "powerSource": false, + "lightValue": 7, + "hardness": 22.5, + "resistance": 600.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:farmland", + "localizedName": "Farmland", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.6, + "resistance": 0.6, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#976d4d", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:fern", + "localizedName": "Fern", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:fire", + "localizedName": "Fire", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:fire_coral", + "localizedName": "Fire Coral", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:fire_coral_block", + "localizedName": "Fire Coral Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:fire_coral_fan", + "localizedName": "Fire Coral Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:fire_coral_wall_fan", + "localizedName": "Fire Coral Wall Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:fletching_table", + "localizedName": "Fletching Table", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:flower_pot", + "localizedName": "Flower Pot", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:frosted_ice", + "localizedName": "Frosted Ice", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.98, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a0a0ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:furnace", + "localizedName": "Furnace", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:glass", + "localizedName": "Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:glass_pane", + "localizedName": "Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:glowstone", + "localizedName": "Glowstone", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gold_block", + "localizedName": "Block of Gold", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gold_ore", + "localizedName": "Gold Ore", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:granite", + "localizedName": "Granite", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:granite_slab", + "localizedName": "Granite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:granite_stairs", + "localizedName": "Granite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:granite_wall", + "localizedName": "Granite Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:grass", + "localizedName": "Grass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:grass_block", + "localizedName": "Grass Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.6, + "resistance": 0.6, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7fb238", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:grass_path", + "localizedName": "Grass Path", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.65, + "resistance": 0.65, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#976d4d", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gravel", + "localizedName": "Gravel", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.6, + "resistance": 0.6, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_banner", + "localizedName": "Gray Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_bed", + "localizedName": "Gray Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_carpet", + "localizedName": "Gray Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_concrete", + "localizedName": "Gray Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_concrete_powder", + "localizedName": "Gray Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_glazed_terracotta", + "localizedName": "Gray Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_shulker_box", + "localizedName": "Gray Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:gray_stained_glass", + "localizedName": "Gray Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_stained_glass_pane", + "localizedName": "Gray Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_terracotta", + "localizedName": "Gray Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_wall_banner", + "localizedName": "Gray Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:gray_wool", + "localizedName": "Gray Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_banner", + "localizedName": "Green Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_bed", + "localizedName": "Green Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_carpet", + "localizedName": "Green Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_concrete", + "localizedName": "Green Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_concrete_powder", + "localizedName": "Green Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_glazed_terracotta", + "localizedName": "Green Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_shulker_box", + "localizedName": "Green Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:green_stained_glass", + "localizedName": "Green Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_stained_glass_pane", + "localizedName": "Green Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_terracotta", + "localizedName": "Green Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_wall_banner", + "localizedName": "Green Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:green_wool", + "localizedName": "Green Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:grindstone", + "localizedName": "Grindstone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:hay_block", + "localizedName": "Hay Bale", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7fb238", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:heavy_weighted_pressure_plate", + "localizedName": "Heavy Weighted Pressure Plate", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:hopper", + "localizedName": "Hopper", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 4.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:horn_coral", + "localizedName": "Horn Coral", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:horn_coral_block", + "localizedName": "Horn Coral Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:horn_coral_fan", + "localizedName": "Horn Coral Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:horn_coral_wall_fan", + "localizedName": "Horn Coral Wall Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:ice", + "localizedName": "Ice", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.98, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a0a0ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:infested_chiseled_stone_bricks", + "localizedName": "Infested Chiseled Stone Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.75, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a4a8b8", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:infested_cobblestone", + "localizedName": "Infested Cobblestone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.75, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a4a8b8", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:infested_cracked_stone_bricks", + "localizedName": "Infested Cracked Stone Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.75, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a4a8b8", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:infested_mossy_stone_bricks", + "localizedName": "Infested Mossy Stone Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.75, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a4a8b8", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:infested_stone", + "localizedName": "Infested Stone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.75, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a4a8b8", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:infested_stone_bricks", + "localizedName": "Infested Stone Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.75, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a4a8b8", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:iron_bars", + "localizedName": "Iron Bars", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:iron_block", + "localizedName": "Block of Iron", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:iron_door", + "localizedName": "Iron Door", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 5.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:iron_ore", + "localizedName": "Iron Ore", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:iron_trapdoor", + "localizedName": "Iron Trapdoor", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 5.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jack_o_lantern", + "localizedName": "Jack o\u0027Lantern", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jigsaw", + "localizedName": "Jigsaw Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": -1.0, + "resistance": 3600000.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jukebox", + "localizedName": "Jukebox", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:jungle_button", + "localizedName": "Jungle Button", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_door", + "localizedName": "Jungle Door", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_fence", + "localizedName": "Jungle Fence", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_fence_gate", + "localizedName": "Jungle Fence Gate", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_leaves", + "localizedName": "Jungle Leaves", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_log", + "localizedName": "Jungle Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_planks", + "localizedName": "Jungle Planks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_pressure_plate", + "localizedName": "Jungle Pressure Plate", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_sapling", + "localizedName": "Jungle Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_sign", + "localizedName": "Jungle Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_slab", + "localizedName": "Jungle Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_stairs", + "localizedName": "Jungle Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_trapdoor", + "localizedName": "Jungle Trapdoor", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_wall_sign", + "localizedName": "Jungle Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:jungle_wood", + "localizedName": "Jungle Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:kelp", + "localizedName": "Kelp", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:kelp_plant", + "localizedName": "Kelp Plant", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:ladder", + "localizedName": "Ladder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.4, + "resistance": 0.4, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lantern", + "localizedName": "Lantern", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lapis_block", + "localizedName": "Lapis Lazuli Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lapis_ore", + "localizedName": "Lapis Lazuli Ore", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:large_fern", + "localizedName": "Large Fern", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lava", + "localizedName": "Lava", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 100.0, + "resistance": 100.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": true, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#ff0000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lectern", + "localizedName": "Lectern", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:lever", + "localizedName": "Lever", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_banner", + "localizedName": "Light Blue Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_bed", + "localizedName": "Light Blue Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_carpet", + "localizedName": "Light Blue Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_concrete", + "localizedName": "Light Blue Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_concrete_powder", + "localizedName": "Light Blue Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_glazed_terracotta", + "localizedName": "Light Blue Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_shulker_box", + "localizedName": "Light Blue Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:light_blue_stained_glass", + "localizedName": "Light Blue Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_stained_glass_pane", + "localizedName": "Light Blue Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_terracotta", + "localizedName": "Light Blue Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_wall_banner", + "localizedName": "Light Blue Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_blue_wool", + "localizedName": "Light Blue Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_banner", + "localizedName": "Light Gray Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_bed", + "localizedName": "Light Gray Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_carpet", + "localizedName": "Light Gray Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_concrete", + "localizedName": "Light Gray Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_concrete_powder", + "localizedName": "Light Gray Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_glazed_terracotta", + "localizedName": "Light Gray Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_shulker_box", + "localizedName": "Light Gray Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:light_gray_stained_glass", + "localizedName": "Light Gray Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_stained_glass_pane", + "localizedName": "Light Gray Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_terracotta", + "localizedName": "Light Gray Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_wall_banner", + "localizedName": "Light Gray Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_gray_wool", + "localizedName": "Light Gray Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:light_weighted_pressure_plate", + "localizedName": "Light Weighted Pressure Plate", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lilac", + "localizedName": "Lilac", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lily_of_the_valley", + "localizedName": "Lily of the Valley", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lily_pad", + "localizedName": "Lily Pad", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_banner", + "localizedName": "Lime Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_bed", + "localizedName": "Lime Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_carpet", + "localizedName": "Lime Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_concrete", + "localizedName": "Lime Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_concrete_powder", + "localizedName": "Lime Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_glazed_terracotta", + "localizedName": "Lime Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_shulker_box", + "localizedName": "Lime Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:lime_stained_glass", + "localizedName": "Lime Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_stained_glass_pane", + "localizedName": "Lime Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_terracotta", + "localizedName": "Lime Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_wall_banner", + "localizedName": "Lime Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:lime_wool", + "localizedName": "Lime Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:loom", + "localizedName": "Loom", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_banner", + "localizedName": "Magenta Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_bed", + "localizedName": "Magenta Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_carpet", + "localizedName": "Magenta Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_concrete", + "localizedName": "Magenta Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_concrete_powder", + "localizedName": "Magenta Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_glazed_terracotta", + "localizedName": "Magenta Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_shulker_box", + "localizedName": "Magenta Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:magenta_stained_glass", + "localizedName": "Magenta Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_stained_glass_pane", + "localizedName": "Magenta Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_terracotta", + "localizedName": "Magenta Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_wall_banner", + "localizedName": "Magenta Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magenta_wool", + "localizedName": "Magenta Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:magma_block", + "localizedName": "Magma Block", + "material": { + "powerSource": false, + "lightValue": 3, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:melon", + "localizedName": "Melon", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:melon_stem", + "localizedName": "Melon Stem", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_cobblestone", + "localizedName": "Mossy Cobblestone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_cobblestone_slab", + "localizedName": "Mossy Cobblestone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_cobblestone_stairs", + "localizedName": "Mossy Cobblestone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_cobblestone_wall", + "localizedName": "Mossy Cobblestone Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_stone_brick_slab", + "localizedName": "Mossy Stone Brick Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_stone_brick_stairs", + "localizedName": "Mossy Stone Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_stone_brick_wall", + "localizedName": "Mossy Stone Brick Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mossy_stone_bricks", + "localizedName": "Mossy Stone Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:moving_piston", + "localizedName": "Moving Piston", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": -1.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#707070", + "isTranslucent": true, + "hasContainer": false + } + }, + { + "id": "minecraft:mushroom_stem", + "localizedName": "Mushroom Stem", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:mycelium", + "localizedName": "Mycelium", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.6, + "resistance": 0.6, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7fb238", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:nether_brick_fence", + "localizedName": "Nether Brick Fence", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:nether_brick_slab", + "localizedName": "Nether Brick Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:nether_brick_stairs", + "localizedName": "Nether Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:nether_brick_wall", + "localizedName": "Nether Brick Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:nether_bricks", + "localizedName": "Nether Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:nether_portal", + "localizedName": "Nether Portal", + "material": { + "powerSource": false, + "lightValue": 11, + "hardness": -1.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:nether_quartz_ore", + "localizedName": "Nether Quartz Ore", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:nether_wart", + "localizedName": "Nether Wart", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:nether_wart_block", + "localizedName": "Nether Wart Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7fb238", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:netherrack", + "localizedName": "Netherrack", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.4, + "resistance": 0.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:note_block", + "localizedName": "Note Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_button", + "localizedName": "Oak Button", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_door", + "localizedName": "Oak Door", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_fence", + "localizedName": "Oak Fence", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_fence_gate", + "localizedName": "Oak Fence Gate", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_leaves", + "localizedName": "Oak Leaves", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_log", + "localizedName": "Oak Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_planks", + "localizedName": "Oak Planks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_pressure_plate", + "localizedName": "Oak Pressure Plate", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_sapling", + "localizedName": "Oak Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_sign", + "localizedName": "Oak Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_slab", + "localizedName": "Oak Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_stairs", + "localizedName": "Oak Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_trapdoor", + "localizedName": "Oak Trapdoor", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_wall_sign", + "localizedName": "Oak Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oak_wood", + "localizedName": "Oak Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:observer", + "localizedName": "Observer", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:obsidian", + "localizedName": "Obsidian", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 50.0, + "resistance": 1200.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_banner", + "localizedName": "Orange Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_bed", + "localizedName": "Orange Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_carpet", + "localizedName": "Orange Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_concrete", + "localizedName": "Orange Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_concrete_powder", + "localizedName": "Orange Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_glazed_terracotta", + "localizedName": "Orange Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_shulker_box", + "localizedName": "Orange Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:orange_stained_glass", + "localizedName": "Orange Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_stained_glass_pane", + "localizedName": "Orange Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_terracotta", + "localizedName": "Orange Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_tulip", + "localizedName": "Orange Tulip", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_wall_banner", + "localizedName": "Orange Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:orange_wool", + "localizedName": "Orange Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:oxeye_daisy", + "localizedName": "Oxeye Daisy", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:packed_ice", + "localizedName": "Packed Ice", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.98, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a0a0ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:peony", + "localizedName": "Peony", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:petrified_oak_slab", + "localizedName": "Petrified Oak Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_banner", + "localizedName": "Pink Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_bed", + "localizedName": "Pink Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_carpet", + "localizedName": "Pink Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_concrete", + "localizedName": "Pink Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_concrete_powder", + "localizedName": "Pink Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_glazed_terracotta", + "localizedName": "Pink Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_shulker_box", + "localizedName": "Pink Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:pink_stained_glass", + "localizedName": "Pink Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_stained_glass_pane", + "localizedName": "Pink Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_terracotta", + "localizedName": "Pink Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_tulip", + "localizedName": "Pink Tulip", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_wall_banner", + "localizedName": "Pink Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pink_wool", + "localizedName": "Pink Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:piston", + "localizedName": "Piston", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:piston_head", + "localizedName": "Piston Head", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:player_head", + "localizedName": "Player Head", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:player_wall_head", + "localizedName": "Player Head", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:podzol", + "localizedName": "Podzol", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#976d4d", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_andesite", + "localizedName": "Polished Andesite", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_andesite_slab", + "localizedName": "Polished Andesite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_andesite_stairs", + "localizedName": "Polished Andesite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_diorite", + "localizedName": "Polished Diorite", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_diorite_slab", + "localizedName": "Polished Diorite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_diorite_stairs", + "localizedName": "Polished Diorite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_granite", + "localizedName": "Polished Granite", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_granite_slab", + "localizedName": "Polished Granite Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:polished_granite_stairs", + "localizedName": "Polished Granite Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:poppy", + "localizedName": "Poppy", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potatoes", + "localizedName": "Potatoes", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_acacia_sapling", + "localizedName": "Potted Acacia Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_allium", + "localizedName": "Potted Allium", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_azure_bluet", + "localizedName": "Potted Azure Bluet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_bamboo", + "localizedName": "Potted Bamboo", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_birch_sapling", + "localizedName": "Potted Birch Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_blue_orchid", + "localizedName": "Potted Blue Orchid", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_brown_mushroom", + "localizedName": "Potted Brown Mushroom", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_cactus", + "localizedName": "Potted Cactus", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_cornflower", + "localizedName": "Potted Cornflower", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_dandelion", + "localizedName": "Potted Dandelion", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_dark_oak_sapling", + "localizedName": "Potted Dark Oak Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_dead_bush", + "localizedName": "Potted Dead Bush", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_fern", + "localizedName": "Potted Fern", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_jungle_sapling", + "localizedName": "Potted Jungle Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_lily_of_the_valley", + "localizedName": "Potted Lily of the Valley", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_oak_sapling", + "localizedName": "Potted Oak Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_orange_tulip", + "localizedName": "Potted Orange Tulip", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_oxeye_daisy", + "localizedName": "Potted Oxeye Daisy", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_pink_tulip", + "localizedName": "Potted Pink Tulip", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_poppy", + "localizedName": "Potted Poppy", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_red_mushroom", + "localizedName": "Potted Red Mushroom", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_red_tulip", + "localizedName": "Potted Red Tulip", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_spruce_sapling", + "localizedName": "Potted Spruce Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_white_tulip", + "localizedName": "Potted White Tulip", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:potted_wither_rose", + "localizedName": "Potted Wither Rose", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:powered_rail", + "localizedName": "Powered Rail", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.7, + "resistance": 0.7, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:prismarine", + "localizedName": "Prismarine", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:prismarine_brick_slab", + "localizedName": "Prismarine Brick Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:prismarine_brick_stairs", + "localizedName": "Prismarine Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:prismarine_bricks", + "localizedName": "Prismarine Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:prismarine_slab", + "localizedName": "Prismarine Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:prismarine_stairs", + "localizedName": "Prismarine Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:prismarine_wall", + "localizedName": "Prismarine Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pumpkin", + "localizedName": "Pumpkin", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:pumpkin_stem", + "localizedName": "Pumpkin Stem", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_banner", + "localizedName": "Purple Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_bed", + "localizedName": "Purple Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_carpet", + "localizedName": "Purple Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_concrete", + "localizedName": "Purple Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_concrete_powder", + "localizedName": "Purple Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_glazed_terracotta", + "localizedName": "Purple Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_shulker_box", + "localizedName": "Purple Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:purple_stained_glass", + "localizedName": "Purple Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_stained_glass_pane", + "localizedName": "Purple Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_terracotta", + "localizedName": "Purple Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_wall_banner", + "localizedName": "Purple Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purple_wool", + "localizedName": "Purple Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purpur_block", + "localizedName": "Purpur Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purpur_pillar", + "localizedName": "Purpur Pillar", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purpur_slab", + "localizedName": "Purpur Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:purpur_stairs", + "localizedName": "Purpur Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:quartz_block", + "localizedName": "Block of Quartz", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:quartz_pillar", + "localizedName": "Quartz Pillar", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:quartz_slab", + "localizedName": "Quartz Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:quartz_stairs", + "localizedName": "Quartz Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:rail", + "localizedName": "Rail", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.7, + "resistance": 0.7, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_banner", + "localizedName": "Red Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_bed", + "localizedName": "Red Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_carpet", + "localizedName": "Red Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_concrete", + "localizedName": "Red Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_concrete_powder", + "localizedName": "Red Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_glazed_terracotta", + "localizedName": "Red Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_mushroom", + "localizedName": "Red Mushroom", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_mushroom_block", + "localizedName": "Red Mushroom Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_nether_brick_slab", + "localizedName": "Red Nether Brick Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_nether_brick_stairs", + "localizedName": "Red Nether Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_nether_brick_wall", + "localizedName": "Red Nether Brick Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_nether_bricks", + "localizedName": "Red Nether Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_sand", + "localizedName": "Red Sand", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_sandstone", + "localizedName": "Red Sandstone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_sandstone_slab", + "localizedName": "Red Sandstone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_sandstone_stairs", + "localizedName": "Red Sandstone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_sandstone_wall", + "localizedName": "Red Sandstone Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_shulker_box", + "localizedName": "Red Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:red_stained_glass", + "localizedName": "Red Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_stained_glass_pane", + "localizedName": "Red Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_terracotta", + "localizedName": "Red Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_tulip", + "localizedName": "Red Tulip", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_wall_banner", + "localizedName": "Red Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:red_wool", + "localizedName": "Red Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:redstone_block", + "localizedName": "Block of Redstone", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 5.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:redstone_lamp", + "localizedName": "Redstone Lamp", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:redstone_ore", + "localizedName": "Redstone Ore", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:redstone_torch", + "localizedName": "Redstone Torch", + "material": { + "powerSource": true, + "lightValue": 7, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:redstone_wall_torch", + "localizedName": "Redstone Torch", + "material": { + "powerSource": true, + "lightValue": 7, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:redstone_wire", + "localizedName": "Redstone Wire", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:repeater", + "localizedName": "Redstone Repeater", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:repeating_command_block", + "localizedName": "Repeating Command Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": -1.0, + "resistance": 3600000.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:rose_bush", + "localizedName": "Rose Bush", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sand", + "localizedName": "Sand", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sandstone", + "localizedName": "Sandstone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sandstone_slab", + "localizedName": "Sandstone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sandstone_stairs", + "localizedName": "Sandstone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sandstone_wall", + "localizedName": "Sandstone Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:scaffolding", + "localizedName": "Scaffolding", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": true, + "hasContainer": false + } + }, + { + "id": "minecraft:sea_lantern", + "localizedName": "Sea Lantern", + "material": { + "powerSource": false, + "lightValue": 15, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sea_pickle", + "localizedName": "Sea Pickle", + "material": { + "powerSource": false, + "lightValue": 6, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:seagrass", + "localizedName": "Seagrass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:shulker_box", + "localizedName": "Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:skeleton_skull", + "localizedName": "Skeleton Skull", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:skeleton_wall_skull", + "localizedName": "Skeleton Skull", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:slime_block", + "localizedName": "Slime Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.8, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a4a8b8", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smithing_table", + "localizedName": "Smithing Table", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smoker", + "localizedName": "Smoker", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:smooth_quartz", + "localizedName": "Smooth Quartz", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_quartz_slab", + "localizedName": "Smooth Quartz Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_quartz_stairs", + "localizedName": "Smooth Quartz Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_red_sandstone", + "localizedName": "Smooth Red Sandstone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_red_sandstone_slab", + "localizedName": "Smooth Red Sandstone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_red_sandstone_stairs", + "localizedName": "Smooth Red Sandstone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_sandstone", + "localizedName": "Smooth Sandstone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_sandstone_slab", + "localizedName": "Smooth Sandstone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_sandstone_stairs", + "localizedName": "Smooth Sandstone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_stone", + "localizedName": "Smooth Stone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:smooth_stone_slab", + "localizedName": "Smooth Stone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:snow", + "localizedName": "Snow", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": true, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#ffffff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:snow_block", + "localizedName": "Snow Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#ffffff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:soul_sand", + "localizedName": "Soul Sand", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spawner", + "localizedName": "Spawner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 5.0, + "resistance": 5.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sponge", + "localizedName": "Sponge", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.6, + "resistance": 0.6, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#e5e533", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_button", + "localizedName": "Spruce Button", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_door", + "localizedName": "Spruce Door", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_fence", + "localizedName": "Spruce Fence", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_fence_gate", + "localizedName": "Spruce Fence Gate", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_leaves", + "localizedName": "Spruce Leaves", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": true, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_log", + "localizedName": "Spruce Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_planks", + "localizedName": "Spruce Planks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_pressure_plate", + "localizedName": "Spruce Pressure Plate", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_sapling", + "localizedName": "Spruce Sapling", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_sign", + "localizedName": "Spruce Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_slab", + "localizedName": "Spruce Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_stairs", + "localizedName": "Spruce Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_trapdoor", + "localizedName": "Spruce Trapdoor", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.0, + "resistance": 3.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_wall_sign", + "localizedName": "Spruce Sign", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:spruce_wood", + "localizedName": "Spruce Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sticky_piston", + "localizedName": "Sticky Piston", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": true, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stone", + "localizedName": "Stone", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stone_brick_slab", + "localizedName": "Stone Brick Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stone_brick_stairs", + "localizedName": "Stone Brick Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stone_brick_wall", + "localizedName": "Stone Brick Wall", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stone_bricks", + "localizedName": "Stone Bricks", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stone_button", + "localizedName": "Stone Button", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stone_pressure_plate", + "localizedName": "Stone Pressure Plate", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stone_slab", + "localizedName": "Stone Slab", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stone_stairs", + "localizedName": "Stone Stairs", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stonecutter", + "localizedName": "Stonecutter", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 3.5, + "resistance": 3.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_acacia_log", + "localizedName": "Stripped Acacia Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_acacia_wood", + "localizedName": "Stripped Acacia Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_birch_log", + "localizedName": "Stripped Birch Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_birch_wood", + "localizedName": "Stripped Birch Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_dark_oak_log", + "localizedName": "Stripped Dark Oak Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_dark_oak_wood", + "localizedName": "Stripped Dark Oak Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_jungle_log", + "localizedName": "Stripped Jungle Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_jungle_wood", + "localizedName": "Stripped Jungle Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_oak_log", + "localizedName": "Stripped Oak Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_oak_wood", + "localizedName": "Stripped Oak Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_spruce_log", + "localizedName": "Stripped Spruce Log", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:stripped_spruce_wood", + "localizedName": "Stripped Spruce Wood", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:structure_block", + "localizedName": "Structure Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": -1.0, + "resistance": 3600000.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#a7a7a7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:structure_void", + "localizedName": "Structure Void", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sugar_cane", + "localizedName": "Sugar Cane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sunflower", + "localizedName": "Sunflower", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:sweet_berry_bush", + "localizedName": "Sweet Berry Bush", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:tall_grass", + "localizedName": "Tall Grass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:tall_seagrass", + "localizedName": "Tall Seagrass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:terracotta", + "localizedName": "Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:tnt", + "localizedName": "TNT", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#ff0000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:torch", + "localizedName": "Torch", + "material": { + "powerSource": false, + "lightValue": 14, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:trapped_chest", + "localizedName": "Trapped Chest", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 2.5, + "resistance": 2.5, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": true + } + }, + { + "id": "minecraft:tripwire", + "localizedName": "Tripwire", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:tripwire_hook", + "localizedName": "Tripwire Hook", + "material": { + "powerSource": true, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:tube_coral", + "localizedName": "Tube Coral", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:tube_coral_block", + "localizedName": "Tube Coral Block", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.5, + "resistance": 6.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:tube_coral_fan", + "localizedName": "Tube Coral Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:tube_coral_wall_fan", + "localizedName": "Tube Coral Wall Fan", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:turtle_egg", + "localizedName": "Turtle Egg", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:vine", + "localizedName": "Vines", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:void_air", + "localizedName": "Void Air", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:wall_torch", + "localizedName": "Torch", + "material": { + "powerSource": false, + "lightValue": 14, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:water", + "localizedName": "Water", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 100.0, + "resistance": 100.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": true, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": true, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#4040ff", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:wet_sponge", + "localizedName": "Wet Sponge", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.6, + "resistance": 0.6, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#e5e533", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:wheat", + "localizedName": "Wheat Crops", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": true, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_banner", + "localizedName": "White Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_bed", + "localizedName": "White Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_carpet", + "localizedName": "White Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_concrete", + "localizedName": "White Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_concrete_powder", + "localizedName": "White Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_glazed_terracotta", + "localizedName": "White Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_shulker_box", + "localizedName": "White Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:white_stained_glass", + "localizedName": "White Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_stained_glass_pane", + "localizedName": "White Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_terracotta", + "localizedName": "White Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_tulip", + "localizedName": "White Tulip", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_wall_banner", + "localizedName": "White Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:white_wool", + "localizedName": "White Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:wither_rose", + "localizedName": "Wither Rose", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.0, + "resistance": 0.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#007c00", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:wither_skeleton_skull", + "localizedName": "Wither Skeleton Skull", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:wither_skeleton_wall_skull", + "localizedName": "Wither Skeleton Skull", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_banner", + "localizedName": "Yellow Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_bed", + "localizedName": "Yellow Bed", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.2, + "resistance": 0.2, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_carpet", + "localizedName": "Yellow Carpet", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.1, + "resistance": 0.1, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": true, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_concrete", + "localizedName": "Yellow Concrete", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.8, + "resistance": 1.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_concrete_powder", + "localizedName": "Yellow Concrete Powder", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.5, + "resistance": 0.5, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#f7e9a3", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_glazed_terracotta", + "localizedName": "Yellow Glazed Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.4, + "resistance": 1.4, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_shulker_box", + "localizedName": "Yellow Shulker Box", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 2.0, + "resistance": 2.0, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#7f3fb2", + "isTranslucent": true, + "hasContainer": true + } + }, + { + "id": "minecraft:yellow_stained_glass", + "localizedName": "Yellow Stained Glass", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_stained_glass_pane", + "localizedName": "Yellow Stained Glass Pane", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.3, + "resistance": 0.3, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_terracotta", + "localizedName": "Yellow Terracotta", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.25, + "resistance": 4.2, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": false, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": true, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#707070", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_wall_banner", + "localizedName": "Yellow Banner", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#8f7748", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:yellow_wool", + "localizedName": "Yellow Wool", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 0.8, + "resistance": 0.8, + "ticksRandomly": false, + "fullCube": true, + "slipperiness": 0.6, + "liquid": false, + "solid": true, + "movementBlocker": true, + "burnable": true, + "opaque": true, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": false, + "unpushable": false, + "mapColor": "#c7c7c7", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:zombie_head", + "localizedName": "Zombie Head", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + }, + { + "id": "minecraft:zombie_wall_head", + "localizedName": "Zombie Head", + "material": { + "powerSource": false, + "lightValue": 0, + "hardness": 1.0, + "resistance": 1.0, + "ticksRandomly": false, + "fullCube": false, + "slipperiness": 0.6, + "liquid": false, + "solid": false, + "movementBlocker": false, + "burnable": false, + "opaque": false, + "replacedDuringPlacement": false, + "toolRequired": false, + "fragileWhenPushed": true, + "unpushable": false, + "mapColor": "#000000", + "isTranslucent": false, + "hasContainer": false + } + } +] \ No newline at end of file diff --git a/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.114.json b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.114.json new file mode 100644 index 000000000..f139d1082 --- /dev/null +++ b/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/items.114.json @@ -0,0 +1,6141 @@ +[ + { + "id": "minecraft:acacia_boat", + "unlocalizedName": "item.minecraft.acacia_boat", + "localizedName": "Acacia Boat", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_button", + "unlocalizedName": "block.minecraft.acacia_button", + "localizedName": "Acacia Button", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_door", + "unlocalizedName": "block.minecraft.acacia_door", + "localizedName": "Acacia Door", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_fence", + "unlocalizedName": "block.minecraft.acacia_fence", + "localizedName": "Acacia Fence", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_fence_gate", + "unlocalizedName": "block.minecraft.acacia_fence_gate", + "localizedName": "Acacia Fence Gate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_leaves", + "unlocalizedName": "block.minecraft.acacia_leaves", + "localizedName": "Acacia Leaves", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_log", + "unlocalizedName": "block.minecraft.acacia_log", + "localizedName": "Acacia Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_planks", + "unlocalizedName": "block.minecraft.acacia_planks", + "localizedName": "Acacia Planks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_pressure_plate", + "unlocalizedName": "block.minecraft.acacia_pressure_plate", + "localizedName": "Acacia Pressure Plate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_sapling", + "unlocalizedName": "block.minecraft.acacia_sapling", + "localizedName": "Acacia Sapling", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_sign", + "unlocalizedName": "block.minecraft.acacia_sign", + "localizedName": "Acacia Sign", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_slab", + "unlocalizedName": "block.minecraft.acacia_slab", + "localizedName": "Acacia Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_stairs", + "unlocalizedName": "block.minecraft.acacia_stairs", + "localizedName": "Acacia Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_trapdoor", + "unlocalizedName": "block.minecraft.acacia_trapdoor", + "localizedName": "Acacia Trapdoor", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:acacia_wood", + "unlocalizedName": "block.minecraft.acacia_wood", + "localizedName": "Acacia Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:activator_rail", + "unlocalizedName": "block.minecraft.activator_rail", + "localizedName": "Activator Rail", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:air", + "unlocalizedName": "block.minecraft.air", + "localizedName": "Air", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:allium", + "unlocalizedName": "block.minecraft.allium", + "localizedName": "Allium", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:andesite", + "unlocalizedName": "block.minecraft.andesite", + "localizedName": "Andesite", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:andesite_slab", + "unlocalizedName": "block.minecraft.andesite_slab", + "localizedName": "Andesite Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:andesite_stairs", + "unlocalizedName": "block.minecraft.andesite_stairs", + "localizedName": "Andesite Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:andesite_wall", + "unlocalizedName": "block.minecraft.andesite_wall", + "localizedName": "Andesite Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:anvil", + "unlocalizedName": "block.minecraft.anvil", + "localizedName": "Anvil", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:apple", + "unlocalizedName": "item.minecraft.apple", + "localizedName": "Apple", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:armor_stand", + "unlocalizedName": "item.minecraft.armor_stand", + "localizedName": "Armor Stand", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:arrow", + "unlocalizedName": "item.minecraft.arrow", + "localizedName": "Arrow", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:azure_bluet", + "unlocalizedName": "block.minecraft.azure_bluet", + "localizedName": "Azure Bluet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:baked_potato", + "unlocalizedName": "item.minecraft.baked_potato", + "localizedName": "Baked Potato", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bamboo", + "unlocalizedName": "block.minecraft.bamboo", + "localizedName": "Bamboo", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:barrel", + "unlocalizedName": "block.minecraft.barrel", + "localizedName": "Barrel", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:barrier", + "unlocalizedName": "block.minecraft.barrier", + "localizedName": "Barrier", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bat_spawn_egg", + "unlocalizedName": "item.minecraft.bat_spawn_egg", + "localizedName": "Bat Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:beacon", + "unlocalizedName": "block.minecraft.beacon", + "localizedName": "Beacon", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bedrock", + "unlocalizedName": "block.minecraft.bedrock", + "localizedName": "Bedrock", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:beef", + "unlocalizedName": "item.minecraft.beef", + "localizedName": "Raw Beef", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:beetroot", + "unlocalizedName": "item.minecraft.beetroot", + "localizedName": "Beetroot", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:beetroot_seeds", + "unlocalizedName": "item.minecraft.beetroot_seeds", + "localizedName": "Beetroot Seeds", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:beetroot_soup", + "unlocalizedName": "item.minecraft.beetroot_soup", + "localizedName": "Beetroot Soup", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:bell", + "unlocalizedName": "block.minecraft.bell", + "localizedName": "Bell", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_boat", + "unlocalizedName": "item.minecraft.birch_boat", + "localizedName": "Birch Boat", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_button", + "unlocalizedName": "block.minecraft.birch_button", + "localizedName": "Birch Button", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_door", + "unlocalizedName": "block.minecraft.birch_door", + "localizedName": "Birch Door", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_fence", + "unlocalizedName": "block.minecraft.birch_fence", + "localizedName": "Birch Fence", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_fence_gate", + "unlocalizedName": "block.minecraft.birch_fence_gate", + "localizedName": "Birch Fence Gate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_leaves", + "unlocalizedName": "block.minecraft.birch_leaves", + "localizedName": "Birch Leaves", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_log", + "unlocalizedName": "block.minecraft.birch_log", + "localizedName": "Birch Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_planks", + "unlocalizedName": "block.minecraft.birch_planks", + "localizedName": "Birch Planks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_pressure_plate", + "unlocalizedName": "block.minecraft.birch_pressure_plate", + "localizedName": "Birch Pressure Plate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_sapling", + "unlocalizedName": "block.minecraft.birch_sapling", + "localizedName": "Birch Sapling", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_sign", + "unlocalizedName": "block.minecraft.birch_sign", + "localizedName": "Birch Sign", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_slab", + "unlocalizedName": "block.minecraft.birch_slab", + "localizedName": "Birch Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_stairs", + "unlocalizedName": "block.minecraft.birch_stairs", + "localizedName": "Birch Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_trapdoor", + "unlocalizedName": "block.minecraft.birch_trapdoor", + "localizedName": "Birch Trapdoor", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:birch_wood", + "unlocalizedName": "block.minecraft.birch_wood", + "localizedName": "Birch Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:black_banner", + "unlocalizedName": "block.minecraft.black_banner", + "localizedName": "Black Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:black_bed", + "unlocalizedName": "block.minecraft.black_bed", + "localizedName": "Black Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:black_carpet", + "unlocalizedName": "block.minecraft.black_carpet", + "localizedName": "Black Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:black_concrete", + "unlocalizedName": "block.minecraft.black_concrete", + "localizedName": "Black Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:black_concrete_powder", + "unlocalizedName": "block.minecraft.black_concrete_powder", + "localizedName": "Black Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:black_dye", + "unlocalizedName": "item.minecraft.black_dye", + "localizedName": "Black Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:black_glazed_terracotta", + "unlocalizedName": "block.minecraft.black_glazed_terracotta", + "localizedName": "Black Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:black_shulker_box", + "unlocalizedName": "block.minecraft.black_shulker_box", + "localizedName": "Black Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:black_stained_glass", + "unlocalizedName": "block.minecraft.black_stained_glass", + "localizedName": "Black Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:black_stained_glass_pane", + "unlocalizedName": "block.minecraft.black_stained_glass_pane", + "localizedName": "Black Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:black_terracotta", + "unlocalizedName": "block.minecraft.black_terracotta", + "localizedName": "Black Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:black_wool", + "unlocalizedName": "block.minecraft.black_wool", + "localizedName": "Black Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blast_furnace", + "unlocalizedName": "block.minecraft.blast_furnace", + "localizedName": "Blast Furnace", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blaze_powder", + "unlocalizedName": "item.minecraft.blaze_powder", + "localizedName": "Blaze Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blaze_rod", + "unlocalizedName": "item.minecraft.blaze_rod", + "localizedName": "Blaze Rod", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blaze_spawn_egg", + "unlocalizedName": "item.minecraft.blaze_spawn_egg", + "localizedName": "Blaze Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_banner", + "unlocalizedName": "block.minecraft.blue_banner", + "localizedName": "Blue Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_bed", + "unlocalizedName": "block.minecraft.blue_bed", + "localizedName": "Blue Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_carpet", + "unlocalizedName": "block.minecraft.blue_carpet", + "localizedName": "Blue Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_concrete", + "unlocalizedName": "block.minecraft.blue_concrete", + "localizedName": "Blue Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_concrete_powder", + "unlocalizedName": "block.minecraft.blue_concrete_powder", + "localizedName": "Blue Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_dye", + "unlocalizedName": "item.minecraft.blue_dye", + "localizedName": "Blue Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_glazed_terracotta", + "unlocalizedName": "block.minecraft.blue_glazed_terracotta", + "localizedName": "Blue Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_ice", + "unlocalizedName": "block.minecraft.blue_ice", + "localizedName": "Blue Ice", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_orchid", + "unlocalizedName": "block.minecraft.blue_orchid", + "localizedName": "Blue Orchid", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_shulker_box", + "unlocalizedName": "block.minecraft.blue_shulker_box", + "localizedName": "Blue Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_stained_glass", + "unlocalizedName": "block.minecraft.blue_stained_glass", + "localizedName": "Blue Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_stained_glass_pane", + "unlocalizedName": "block.minecraft.blue_stained_glass_pane", + "localizedName": "Blue Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_terracotta", + "unlocalizedName": "block.minecraft.blue_terracotta", + "localizedName": "Blue Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:blue_wool", + "unlocalizedName": "block.minecraft.blue_wool", + "localizedName": "Blue Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bone", + "unlocalizedName": "item.minecraft.bone", + "localizedName": "Bone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bone_block", + "unlocalizedName": "block.minecraft.bone_block", + "localizedName": "Bone Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bone_meal", + "unlocalizedName": "item.minecraft.bone_meal", + "localizedName": "Bone Meal", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:book", + "unlocalizedName": "item.minecraft.book", + "localizedName": "Book", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bookshelf", + "unlocalizedName": "block.minecraft.bookshelf", + "localizedName": "Bookshelf", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bow", + "unlocalizedName": "item.minecraft.bow", + "localizedName": "Bow", + "maxStackSize": 1, + "maxDamage": 384 + }, + { + "id": "minecraft:bowl", + "unlocalizedName": "item.minecraft.bowl", + "localizedName": "Bowl", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brain_coral", + "unlocalizedName": "block.minecraft.brain_coral", + "localizedName": "Brain Coral", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brain_coral_block", + "unlocalizedName": "block.minecraft.brain_coral_block", + "localizedName": "Brain Coral Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brain_coral_fan", + "unlocalizedName": "block.minecraft.brain_coral_fan", + "localizedName": "Brain Coral Fan", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bread", + "unlocalizedName": "item.minecraft.bread", + "localizedName": "Bread", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brewing_stand", + "unlocalizedName": "block.minecraft.brewing_stand", + "localizedName": "Brewing Stand", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brick", + "unlocalizedName": "item.minecraft.brick", + "localizedName": "Brick", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brick_slab", + "unlocalizedName": "block.minecraft.brick_slab", + "localizedName": "Brick Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brick_stairs", + "unlocalizedName": "block.minecraft.brick_stairs", + "localizedName": "Brick Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brick_wall", + "unlocalizedName": "block.minecraft.brick_wall", + "localizedName": "Brick Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bricks", + "unlocalizedName": "block.minecraft.bricks", + "localizedName": "Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_banner", + "unlocalizedName": "block.minecraft.brown_banner", + "localizedName": "Brown Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_bed", + "unlocalizedName": "block.minecraft.brown_bed", + "localizedName": "Brown Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_carpet", + "unlocalizedName": "block.minecraft.brown_carpet", + "localizedName": "Brown Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_concrete", + "unlocalizedName": "block.minecraft.brown_concrete", + "localizedName": "Brown Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_concrete_powder", + "unlocalizedName": "block.minecraft.brown_concrete_powder", + "localizedName": "Brown Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_dye", + "unlocalizedName": "item.minecraft.brown_dye", + "localizedName": "Brown Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_glazed_terracotta", + "unlocalizedName": "block.minecraft.brown_glazed_terracotta", + "localizedName": "Brown Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_mushroom", + "unlocalizedName": "block.minecraft.brown_mushroom", + "localizedName": "Brown Mushroom", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_mushroom_block", + "unlocalizedName": "block.minecraft.brown_mushroom_block", + "localizedName": "Brown Mushroom Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_shulker_box", + "unlocalizedName": "block.minecraft.brown_shulker_box", + "localizedName": "Brown Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_stained_glass", + "unlocalizedName": "block.minecraft.brown_stained_glass", + "localizedName": "Brown Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_stained_glass_pane", + "unlocalizedName": "block.minecraft.brown_stained_glass_pane", + "localizedName": "Brown Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_terracotta", + "unlocalizedName": "block.minecraft.brown_terracotta", + "localizedName": "Brown Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:brown_wool", + "unlocalizedName": "block.minecraft.brown_wool", + "localizedName": "Brown Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bubble_coral", + "unlocalizedName": "block.minecraft.bubble_coral", + "localizedName": "Bubble Coral", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bubble_coral_block", + "unlocalizedName": "block.minecraft.bubble_coral_block", + "localizedName": "Bubble Coral Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bubble_coral_fan", + "unlocalizedName": "block.minecraft.bubble_coral_fan", + "localizedName": "Bubble Coral Fan", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:bucket", + "unlocalizedName": "item.minecraft.bucket", + "localizedName": "Bucket", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:cactus", + "unlocalizedName": "block.minecraft.cactus", + "localizedName": "Cactus", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cake", + "unlocalizedName": "block.minecraft.cake", + "localizedName": "Cake", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:campfire", + "unlocalizedName": "block.minecraft.campfire", + "localizedName": "Campfire", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:carrot", + "unlocalizedName": "item.minecraft.carrot", + "localizedName": "Carrot", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:carrot_on_a_stick", + "unlocalizedName": "item.minecraft.carrot_on_a_stick", + "localizedName": "Carrot on a Stick", + "maxStackSize": 1, + "maxDamage": 25 + }, + { + "id": "minecraft:cartography_table", + "unlocalizedName": "block.minecraft.cartography_table", + "localizedName": "Cartography Table", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:carved_pumpkin", + "unlocalizedName": "block.minecraft.carved_pumpkin", + "localizedName": "Carved Pumpkin", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cat_spawn_egg", + "unlocalizedName": "item.minecraft.cat_spawn_egg", + "localizedName": "Cat Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cauldron", + "unlocalizedName": "block.minecraft.cauldron", + "localizedName": "Cauldron", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cave_spider_spawn_egg", + "unlocalizedName": "item.minecraft.cave_spider_spawn_egg", + "localizedName": "Cave Spider Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chain_command_block", + "unlocalizedName": "block.minecraft.chain_command_block", + "localizedName": "Chain Command Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chainmail_boots", + "unlocalizedName": "item.minecraft.chainmail_boots", + "localizedName": "Chainmail Boots", + "maxStackSize": 1, + "maxDamage": 195 + }, + { + "id": "minecraft:chainmail_chestplate", + "unlocalizedName": "item.minecraft.chainmail_chestplate", + "localizedName": "Chainmail Chestplate", + "maxStackSize": 1, + "maxDamage": 240 + }, + { + "id": "minecraft:chainmail_helmet", + "unlocalizedName": "item.minecraft.chainmail_helmet", + "localizedName": "Chainmail Helmet", + "maxStackSize": 1, + "maxDamage": 165 + }, + { + "id": "minecraft:chainmail_leggings", + "unlocalizedName": "item.minecraft.chainmail_leggings", + "localizedName": "Chainmail Leggings", + "maxStackSize": 1, + "maxDamage": 225 + }, + { + "id": "minecraft:charcoal", + "unlocalizedName": "item.minecraft.charcoal", + "localizedName": "Charcoal", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chest", + "unlocalizedName": "block.minecraft.chest", + "localizedName": "Chest", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chest_minecart", + "unlocalizedName": "item.minecraft.chest_minecart", + "localizedName": "Minecart with Chest", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:chicken", + "unlocalizedName": "item.minecraft.chicken", + "localizedName": "Raw Chicken", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chicken_spawn_egg", + "unlocalizedName": "item.minecraft.chicken_spawn_egg", + "localizedName": "Chicken Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chipped_anvil", + "unlocalizedName": "block.minecraft.chipped_anvil", + "localizedName": "Chipped Anvil", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chiseled_quartz_block", + "unlocalizedName": "block.minecraft.chiseled_quartz_block", + "localizedName": "Chiseled Quartz Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chiseled_red_sandstone", + "unlocalizedName": "block.minecraft.chiseled_red_sandstone", + "localizedName": "Chiseled Red Sandstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chiseled_sandstone", + "unlocalizedName": "block.minecraft.chiseled_sandstone", + "localizedName": "Chiseled Sandstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chiseled_stone_bricks", + "unlocalizedName": "block.minecraft.chiseled_stone_bricks", + "localizedName": "Chiseled Stone Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chorus_flower", + "unlocalizedName": "block.minecraft.chorus_flower", + "localizedName": "Chorus Flower", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chorus_fruit", + "unlocalizedName": "item.minecraft.chorus_fruit", + "localizedName": "Chorus Fruit", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:chorus_plant", + "unlocalizedName": "block.minecraft.chorus_plant", + "localizedName": "Chorus Plant", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:clay", + "unlocalizedName": "block.minecraft.clay", + "localizedName": "Clay", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:clay_ball", + "unlocalizedName": "item.minecraft.clay_ball", + "localizedName": "Clay", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:clock", + "unlocalizedName": "item.minecraft.clock", + "localizedName": "Clock", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:coal", + "unlocalizedName": "item.minecraft.coal", + "localizedName": "Coal", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:coal_block", + "unlocalizedName": "block.minecraft.coal_block", + "localizedName": "Block of Coal", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:coal_ore", + "unlocalizedName": "block.minecraft.coal_ore", + "localizedName": "Coal Ore", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:coarse_dirt", + "unlocalizedName": "block.minecraft.coarse_dirt", + "localizedName": "Coarse Dirt", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cobblestone", + "unlocalizedName": "block.minecraft.cobblestone", + "localizedName": "Cobblestone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cobblestone_slab", + "unlocalizedName": "block.minecraft.cobblestone_slab", + "localizedName": "Cobblestone Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cobblestone_stairs", + "unlocalizedName": "block.minecraft.cobblestone_stairs", + "localizedName": "Cobblestone Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cobblestone_wall", + "unlocalizedName": "block.minecraft.cobblestone_wall", + "localizedName": "Cobblestone Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cobweb", + "unlocalizedName": "block.minecraft.cobweb", + "localizedName": "Cobweb", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cocoa_beans", + "unlocalizedName": "item.minecraft.cocoa_beans", + "localizedName": "Cocoa Beans", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cod", + "unlocalizedName": "item.minecraft.cod", + "localizedName": "Raw Cod", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cod_bucket", + "unlocalizedName": "item.minecraft.cod_bucket", + "localizedName": "Bucket of Cod", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:cod_spawn_egg", + "unlocalizedName": "item.minecraft.cod_spawn_egg", + "localizedName": "Cod Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:command_block", + "unlocalizedName": "block.minecraft.command_block", + "localizedName": "Command Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:command_block_minecart", + "unlocalizedName": "item.minecraft.command_block_minecart", + "localizedName": "Minecart with Command Block", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:comparator", + "unlocalizedName": "block.minecraft.comparator", + "localizedName": "Redstone Comparator", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:compass", + "unlocalizedName": "item.minecraft.compass", + "localizedName": "Compass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:composter", + "unlocalizedName": "block.minecraft.composter", + "localizedName": "Composter", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:conduit", + "unlocalizedName": "block.minecraft.conduit", + "localizedName": "Conduit", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cooked_beef", + "unlocalizedName": "item.minecraft.cooked_beef", + "localizedName": "Steak", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cooked_chicken", + "unlocalizedName": "item.minecraft.cooked_chicken", + "localizedName": "Cooked Chicken", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cooked_cod", + "unlocalizedName": "item.minecraft.cooked_cod", + "localizedName": "Cooked Cod", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cooked_mutton", + "unlocalizedName": "item.minecraft.cooked_mutton", + "localizedName": "Cooked Mutton", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cooked_porkchop", + "unlocalizedName": "item.minecraft.cooked_porkchop", + "localizedName": "Cooked Porkchop", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cooked_rabbit", + "unlocalizedName": "item.minecraft.cooked_rabbit", + "localizedName": "Cooked Rabbit", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cooked_salmon", + "unlocalizedName": "item.minecraft.cooked_salmon", + "localizedName": "Cooked Salmon", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cookie", + "unlocalizedName": "item.minecraft.cookie", + "localizedName": "Cookie", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cornflower", + "unlocalizedName": "block.minecraft.cornflower", + "localizedName": "Cornflower", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cow_spawn_egg", + "unlocalizedName": "item.minecraft.cow_spawn_egg", + "localizedName": "Cow Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cracked_stone_bricks", + "unlocalizedName": "block.minecraft.cracked_stone_bricks", + "localizedName": "Cracked Stone Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:crafting_table", + "unlocalizedName": "block.minecraft.crafting_table", + "localizedName": "Crafting Table", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:creeper_banner_pattern", + "unlocalizedName": "item.minecraft.creeper_banner_pattern", + "localizedName": "Banner Pattern", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:creeper_head", + "unlocalizedName": "block.minecraft.creeper_head", + "localizedName": "Creeper Head", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:creeper_spawn_egg", + "unlocalizedName": "item.minecraft.creeper_spawn_egg", + "localizedName": "Creeper Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:crossbow", + "unlocalizedName": "item.minecraft.crossbow", + "localizedName": "Crossbow", + "maxStackSize": 1, + "maxDamage": 326 + }, + { + "id": "minecraft:cut_red_sandstone", + "unlocalizedName": "block.minecraft.cut_red_sandstone", + "localizedName": "Cut Red Sandstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cut_red_sandstone_slab", + "unlocalizedName": "block.minecraft.cut_red_sandstone_slab", + "localizedName": "Cut Red Sandstone Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cut_sandstone", + "unlocalizedName": "block.minecraft.cut_sandstone", + "localizedName": "Cut Sandstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cut_sandstone_slab", + "unlocalizedName": "block.minecraft.cut_sandstone_slab", + "localizedName": "Cut Sandstone Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_banner", + "unlocalizedName": "block.minecraft.cyan_banner", + "localizedName": "Cyan Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_bed", + "unlocalizedName": "block.minecraft.cyan_bed", + "localizedName": "Cyan Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_carpet", + "unlocalizedName": "block.minecraft.cyan_carpet", + "localizedName": "Cyan Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_concrete", + "unlocalizedName": "block.minecraft.cyan_concrete", + "localizedName": "Cyan Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_concrete_powder", + "unlocalizedName": "block.minecraft.cyan_concrete_powder", + "localizedName": "Cyan Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_dye", + "unlocalizedName": "item.minecraft.cyan_dye", + "localizedName": "Cyan Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_glazed_terracotta", + "unlocalizedName": "block.minecraft.cyan_glazed_terracotta", + "localizedName": "Cyan Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_shulker_box", + "unlocalizedName": "block.minecraft.cyan_shulker_box", + "localizedName": "Cyan Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_stained_glass", + "unlocalizedName": "block.minecraft.cyan_stained_glass", + "localizedName": "Cyan Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_stained_glass_pane", + "unlocalizedName": "block.minecraft.cyan_stained_glass_pane", + "localizedName": "Cyan Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_terracotta", + "unlocalizedName": "block.minecraft.cyan_terracotta", + "localizedName": "Cyan Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:cyan_wool", + "unlocalizedName": "block.minecraft.cyan_wool", + "localizedName": "Cyan Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:damaged_anvil", + "unlocalizedName": "block.minecraft.damaged_anvil", + "localizedName": "Damaged Anvil", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dandelion", + "unlocalizedName": "block.minecraft.dandelion", + "localizedName": "Dandelion", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_boat", + "unlocalizedName": "item.minecraft.dark_oak_boat", + "localizedName": "Dark Oak Boat", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_button", + "unlocalizedName": "block.minecraft.dark_oak_button", + "localizedName": "Dark Oak Button", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_door", + "unlocalizedName": "block.minecraft.dark_oak_door", + "localizedName": "Dark Oak Door", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_fence", + "unlocalizedName": "block.minecraft.dark_oak_fence", + "localizedName": "Dark Oak Fence", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_fence_gate", + "unlocalizedName": "block.minecraft.dark_oak_fence_gate", + "localizedName": "Dark Oak Fence Gate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_leaves", + "unlocalizedName": "block.minecraft.dark_oak_leaves", + "localizedName": "Dark Oak Leaves", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_log", + "unlocalizedName": "block.minecraft.dark_oak_log", + "localizedName": "Dark Oak Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_planks", + "unlocalizedName": "block.minecraft.dark_oak_planks", + "localizedName": "Dark Oak Planks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_pressure_plate", + "unlocalizedName": "block.minecraft.dark_oak_pressure_plate", + "localizedName": "Dark Oak Pressure Plate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_sapling", + "unlocalizedName": "block.minecraft.dark_oak_sapling", + "localizedName": "Dark Oak Sapling", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_sign", + "unlocalizedName": "block.minecraft.dark_oak_sign", + "localizedName": "Dark Oak Sign", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_slab", + "unlocalizedName": "block.minecraft.dark_oak_slab", + "localizedName": "Dark Oak Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_stairs", + "unlocalizedName": "block.minecraft.dark_oak_stairs", + "localizedName": "Dark Oak Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_trapdoor", + "unlocalizedName": "block.minecraft.dark_oak_trapdoor", + "localizedName": "Dark Oak Trapdoor", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_oak_wood", + "unlocalizedName": "block.minecraft.dark_oak_wood", + "localizedName": "Dark Oak Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_prismarine", + "unlocalizedName": "block.minecraft.dark_prismarine", + "localizedName": "Dark Prismarine", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_prismarine_slab", + "unlocalizedName": "block.minecraft.dark_prismarine_slab", + "localizedName": "Dark Prismarine Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dark_prismarine_stairs", + "unlocalizedName": "block.minecraft.dark_prismarine_stairs", + "localizedName": "Dark Prismarine Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:daylight_detector", + "unlocalizedName": "block.minecraft.daylight_detector", + "localizedName": "Daylight Detector", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_brain_coral", + "unlocalizedName": "block.minecraft.dead_brain_coral", + "localizedName": "Dead Brain Coral", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_brain_coral_block", + "unlocalizedName": "block.minecraft.dead_brain_coral_block", + "localizedName": "Dead Brain Coral Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_brain_coral_fan", + "unlocalizedName": "block.minecraft.dead_brain_coral_fan", + "localizedName": "Dead Brain Coral Fan", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_bubble_coral", + "unlocalizedName": "block.minecraft.dead_bubble_coral", + "localizedName": "Dead Bubble Coral", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_bubble_coral_block", + "unlocalizedName": "block.minecraft.dead_bubble_coral_block", + "localizedName": "Dead Bubble Coral Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_bubble_coral_fan", + "unlocalizedName": "block.minecraft.dead_bubble_coral_fan", + "localizedName": "Dead Bubble Coral Fan", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_bush", + "unlocalizedName": "block.minecraft.dead_bush", + "localizedName": "Dead Bush", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_fire_coral", + "unlocalizedName": "block.minecraft.dead_fire_coral", + "localizedName": "Dead Fire Coral", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_fire_coral_block", + "unlocalizedName": "block.minecraft.dead_fire_coral_block", + "localizedName": "Dead Fire Coral Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_fire_coral_fan", + "unlocalizedName": "block.minecraft.dead_fire_coral_fan", + "localizedName": "Dead Fire Coral Fan", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_horn_coral", + "unlocalizedName": "block.minecraft.dead_horn_coral", + "localizedName": "Dead Horn Coral", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_horn_coral_block", + "unlocalizedName": "block.minecraft.dead_horn_coral_block", + "localizedName": "Dead Horn Coral Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_horn_coral_fan", + "unlocalizedName": "block.minecraft.dead_horn_coral_fan", + "localizedName": "Dead Horn Coral Fan", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_tube_coral", + "unlocalizedName": "block.minecraft.dead_tube_coral", + "localizedName": "Dead Tube Coral", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_tube_coral_block", + "unlocalizedName": "block.minecraft.dead_tube_coral_block", + "localizedName": "Dead Tube Coral Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dead_tube_coral_fan", + "unlocalizedName": "block.minecraft.dead_tube_coral_fan", + "localizedName": "Dead Tube Coral Fan", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:debug_stick", + "unlocalizedName": "item.minecraft.debug_stick", + "localizedName": "Debug Stick", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:detector_rail", + "unlocalizedName": "block.minecraft.detector_rail", + "localizedName": "Detector Rail", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:diamond", + "unlocalizedName": "item.minecraft.diamond", + "localizedName": "Diamond", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:diamond_axe", + "unlocalizedName": "item.minecraft.diamond_axe", + "localizedName": "Diamond Axe", + "maxStackSize": 1, + "maxDamage": 1561 + }, + { + "id": "minecraft:diamond_block", + "unlocalizedName": "block.minecraft.diamond_block", + "localizedName": "Block of Diamond", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:diamond_boots", + "unlocalizedName": "item.minecraft.diamond_boots", + "localizedName": "Diamond Boots", + "maxStackSize": 1, + "maxDamage": 429 + }, + { + "id": "minecraft:diamond_chestplate", + "unlocalizedName": "item.minecraft.diamond_chestplate", + "localizedName": "Diamond Chestplate", + "maxStackSize": 1, + "maxDamage": 528 + }, + { + "id": "minecraft:diamond_helmet", + "unlocalizedName": "item.minecraft.diamond_helmet", + "localizedName": "Diamond Helmet", + "maxStackSize": 1, + "maxDamage": 363 + }, + { + "id": "minecraft:diamond_hoe", + "unlocalizedName": "item.minecraft.diamond_hoe", + "localizedName": "Diamond Hoe", + "maxStackSize": 1, + "maxDamage": 1561 + }, + { + "id": "minecraft:diamond_horse_armor", + "unlocalizedName": "item.minecraft.diamond_horse_armor", + "localizedName": "Diamond Horse Armor", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:diamond_leggings", + "unlocalizedName": "item.minecraft.diamond_leggings", + "localizedName": "Diamond Leggings", + "maxStackSize": 1, + "maxDamage": 495 + }, + { + "id": "minecraft:diamond_ore", + "unlocalizedName": "block.minecraft.diamond_ore", + "localizedName": "Diamond Ore", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:diamond_pickaxe", + "unlocalizedName": "item.minecraft.diamond_pickaxe", + "localizedName": "Diamond Pickaxe", + "maxStackSize": 1, + "maxDamage": 1561 + }, + { + "id": "minecraft:diamond_shovel", + "unlocalizedName": "item.minecraft.diamond_shovel", + "localizedName": "Diamond Shovel", + "maxStackSize": 1, + "maxDamage": 1561 + }, + { + "id": "minecraft:diamond_sword", + "unlocalizedName": "item.minecraft.diamond_sword", + "localizedName": "Diamond Sword", + "maxStackSize": 1, + "maxDamage": 1561 + }, + { + "id": "minecraft:diorite", + "unlocalizedName": "block.minecraft.diorite", + "localizedName": "Diorite", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:diorite_slab", + "unlocalizedName": "block.minecraft.diorite_slab", + "localizedName": "Diorite Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:diorite_stairs", + "unlocalizedName": "block.minecraft.diorite_stairs", + "localizedName": "Diorite Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:diorite_wall", + "unlocalizedName": "block.minecraft.diorite_wall", + "localizedName": "Diorite Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dirt", + "unlocalizedName": "block.minecraft.dirt", + "localizedName": "Dirt", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dispenser", + "unlocalizedName": "block.minecraft.dispenser", + "localizedName": "Dispenser", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dolphin_spawn_egg", + "unlocalizedName": "item.minecraft.dolphin_spawn_egg", + "localizedName": "Dolphin Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:donkey_spawn_egg", + "unlocalizedName": "item.minecraft.donkey_spawn_egg", + "localizedName": "Donkey Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dragon_breath", + "unlocalizedName": "item.minecraft.dragon_breath", + "localizedName": "Dragon\u0027s Breath", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dragon_egg", + "unlocalizedName": "block.minecraft.dragon_egg", + "localizedName": "Dragon Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dragon_head", + "unlocalizedName": "block.minecraft.dragon_head", + "localizedName": "Dragon Head", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dried_kelp", + "unlocalizedName": "item.minecraft.dried_kelp", + "localizedName": "Dried Kelp", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dried_kelp_block", + "unlocalizedName": "block.minecraft.dried_kelp_block", + "localizedName": "Dried Kelp Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:dropper", + "unlocalizedName": "block.minecraft.dropper", + "localizedName": "Dropper", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:drowned_spawn_egg", + "unlocalizedName": "item.minecraft.drowned_spawn_egg", + "localizedName": "Drowned Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:egg", + "unlocalizedName": "item.minecraft.egg", + "localizedName": "Egg", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:elder_guardian_spawn_egg", + "unlocalizedName": "item.minecraft.elder_guardian_spawn_egg", + "localizedName": "Elder Guardian Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:elytra", + "unlocalizedName": "item.minecraft.elytra", + "localizedName": "Elytra", + "maxStackSize": 1, + "maxDamage": 432 + }, + { + "id": "minecraft:emerald", + "unlocalizedName": "item.minecraft.emerald", + "localizedName": "Emerald", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:emerald_block", + "unlocalizedName": "block.minecraft.emerald_block", + "localizedName": "Block of Emerald", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:emerald_ore", + "unlocalizedName": "block.minecraft.emerald_ore", + "localizedName": "Emerald Ore", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:enchanted_book", + "unlocalizedName": "item.minecraft.enchanted_book", + "localizedName": "Enchanted Book", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:enchanted_golden_apple", + "unlocalizedName": "item.minecraft.enchanted_golden_apple", + "localizedName": "Enchanted Golden Apple", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:enchanting_table", + "unlocalizedName": "block.minecraft.enchanting_table", + "localizedName": "Enchanting Table", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:end_crystal", + "unlocalizedName": "item.minecraft.end_crystal", + "localizedName": "End Crystal", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:end_portal_frame", + "unlocalizedName": "block.minecraft.end_portal_frame", + "localizedName": "End Portal Frame", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:end_rod", + "unlocalizedName": "block.minecraft.end_rod", + "localizedName": "End Rod", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:end_stone", + "unlocalizedName": "block.minecraft.end_stone", + "localizedName": "End Stone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:end_stone_brick_slab", + "unlocalizedName": "block.minecraft.end_stone_brick_slab", + "localizedName": "End Stone Brick Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:end_stone_brick_stairs", + "unlocalizedName": "block.minecraft.end_stone_brick_stairs", + "localizedName": "End Stone Brick Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:end_stone_brick_wall", + "unlocalizedName": "block.minecraft.end_stone_brick_wall", + "localizedName": "End Stone Brick Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:end_stone_bricks", + "unlocalizedName": "block.minecraft.end_stone_bricks", + "localizedName": "End Stone Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:ender_chest", + "unlocalizedName": "block.minecraft.ender_chest", + "localizedName": "Ender Chest", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:ender_eye", + "unlocalizedName": "item.minecraft.ender_eye", + "localizedName": "Eye of Ender", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:ender_pearl", + "unlocalizedName": "item.minecraft.ender_pearl", + "localizedName": "Ender Pearl", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:enderman_spawn_egg", + "unlocalizedName": "item.minecraft.enderman_spawn_egg", + "localizedName": "Enderman Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:endermite_spawn_egg", + "unlocalizedName": "item.minecraft.endermite_spawn_egg", + "localizedName": "Endermite Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:evoker_spawn_egg", + "unlocalizedName": "item.minecraft.evoker_spawn_egg", + "localizedName": "Evoker Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:experience_bottle", + "unlocalizedName": "item.minecraft.experience_bottle", + "localizedName": "Bottle o\u0027 Enchanting", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:farmland", + "unlocalizedName": "block.minecraft.farmland", + "localizedName": "Farmland", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:feather", + "unlocalizedName": "item.minecraft.feather", + "localizedName": "Feather", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:fermented_spider_eye", + "unlocalizedName": "item.minecraft.fermented_spider_eye", + "localizedName": "Fermented Spider Eye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:fern", + "unlocalizedName": "block.minecraft.fern", + "localizedName": "Fern", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:filled_map", + "unlocalizedName": "item.minecraft.filled_map", + "localizedName": "Map", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:fire_charge", + "unlocalizedName": "item.minecraft.fire_charge", + "localizedName": "Fire Charge", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:fire_coral", + "unlocalizedName": "block.minecraft.fire_coral", + "localizedName": "Fire Coral", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:fire_coral_block", + "unlocalizedName": "block.minecraft.fire_coral_block", + "localizedName": "Fire Coral Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:fire_coral_fan", + "unlocalizedName": "block.minecraft.fire_coral_fan", + "localizedName": "Fire Coral Fan", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:firework_rocket", + "unlocalizedName": "item.minecraft.firework_rocket", + "localizedName": "Firework Rocket", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:firework_star", + "unlocalizedName": "item.minecraft.firework_star", + "localizedName": "Firework Star", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:fishing_rod", + "unlocalizedName": "item.minecraft.fishing_rod", + "localizedName": "Fishing Rod", + "maxStackSize": 1, + "maxDamage": 64 + }, + { + "id": "minecraft:fletching_table", + "unlocalizedName": "block.minecraft.fletching_table", + "localizedName": "Fletching Table", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:flint", + "unlocalizedName": "item.minecraft.flint", + "localizedName": "Flint", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:flint_and_steel", + "unlocalizedName": "item.minecraft.flint_and_steel", + "localizedName": "Flint and Steel", + "maxStackSize": 1, + "maxDamage": 64 + }, + { + "id": "minecraft:flower_banner_pattern", + "unlocalizedName": "item.minecraft.flower_banner_pattern", + "localizedName": "Banner Pattern", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:flower_pot", + "unlocalizedName": "block.minecraft.flower_pot", + "localizedName": "Flower Pot", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:fox_spawn_egg", + "unlocalizedName": "item.minecraft.fox_spawn_egg", + "localizedName": "Fox Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:furnace", + "unlocalizedName": "block.minecraft.furnace", + "localizedName": "Furnace", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:furnace_minecart", + "unlocalizedName": "item.minecraft.furnace_minecart", + "localizedName": "Minecart with Furnace", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:ghast_spawn_egg", + "unlocalizedName": "item.minecraft.ghast_spawn_egg", + "localizedName": "Ghast Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:ghast_tear", + "unlocalizedName": "item.minecraft.ghast_tear", + "localizedName": "Ghast Tear", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:glass", + "unlocalizedName": "block.minecraft.glass", + "localizedName": "Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:glass_bottle", + "unlocalizedName": "item.minecraft.glass_bottle", + "localizedName": "Glass Bottle", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:glass_pane", + "unlocalizedName": "block.minecraft.glass_pane", + "localizedName": "Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:glistering_melon_slice", + "unlocalizedName": "item.minecraft.glistering_melon_slice", + "localizedName": "Glistering Melon Slice", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:globe_banner_pattern", + "unlocalizedName": "item.minecraft.globe_banner_pattern", + "localizedName": "Banner Pattern", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:glowstone", + "unlocalizedName": "block.minecraft.glowstone", + "localizedName": "Glowstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:glowstone_dust", + "unlocalizedName": "item.minecraft.glowstone_dust", + "localizedName": "Glowstone Dust", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gold_block", + "unlocalizedName": "block.minecraft.gold_block", + "localizedName": "Block of Gold", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gold_ingot", + "unlocalizedName": "item.minecraft.gold_ingot", + "localizedName": "Gold Ingot", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gold_nugget", + "unlocalizedName": "item.minecraft.gold_nugget", + "localizedName": "Gold Nugget", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gold_ore", + "unlocalizedName": "block.minecraft.gold_ore", + "localizedName": "Gold Ore", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:golden_apple", + "unlocalizedName": "item.minecraft.golden_apple", + "localizedName": "Golden Apple", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:golden_axe", + "unlocalizedName": "item.minecraft.golden_axe", + "localizedName": "Golden Axe", + "maxStackSize": 1, + "maxDamage": 32 + }, + { + "id": "minecraft:golden_boots", + "unlocalizedName": "item.minecraft.golden_boots", + "localizedName": "Golden Boots", + "maxStackSize": 1, + "maxDamage": 91 + }, + { + "id": "minecraft:golden_carrot", + "unlocalizedName": "item.minecraft.golden_carrot", + "localizedName": "Golden Carrot", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:golden_chestplate", + "unlocalizedName": "item.minecraft.golden_chestplate", + "localizedName": "Golden Chestplate", + "maxStackSize": 1, + "maxDamage": 112 + }, + { + "id": "minecraft:golden_helmet", + "unlocalizedName": "item.minecraft.golden_helmet", + "localizedName": "Golden Helmet", + "maxStackSize": 1, + "maxDamage": 77 + }, + { + "id": "minecraft:golden_hoe", + "unlocalizedName": "item.minecraft.golden_hoe", + "localizedName": "Golden Hoe", + "maxStackSize": 1, + "maxDamage": 32 + }, + { + "id": "minecraft:golden_horse_armor", + "unlocalizedName": "item.minecraft.golden_horse_armor", + "localizedName": "Golden Horse Armor", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:golden_leggings", + "unlocalizedName": "item.minecraft.golden_leggings", + "localizedName": "Golden Leggings", + "maxStackSize": 1, + "maxDamage": 105 + }, + { + "id": "minecraft:golden_pickaxe", + "unlocalizedName": "item.minecraft.golden_pickaxe", + "localizedName": "Golden Pickaxe", + "maxStackSize": 1, + "maxDamage": 32 + }, + { + "id": "minecraft:golden_shovel", + "unlocalizedName": "item.minecraft.golden_shovel", + "localizedName": "Golden Shovel", + "maxStackSize": 1, + "maxDamage": 32 + }, + { + "id": "minecraft:golden_sword", + "unlocalizedName": "item.minecraft.golden_sword", + "localizedName": "Golden Sword", + "maxStackSize": 1, + "maxDamage": 32 + }, + { + "id": "minecraft:granite", + "unlocalizedName": "block.minecraft.granite", + "localizedName": "Granite", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:granite_slab", + "unlocalizedName": "block.minecraft.granite_slab", + "localizedName": "Granite Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:granite_stairs", + "unlocalizedName": "block.minecraft.granite_stairs", + "localizedName": "Granite Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:granite_wall", + "unlocalizedName": "block.minecraft.granite_wall", + "localizedName": "Granite Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:grass", + "unlocalizedName": "block.minecraft.grass", + "localizedName": "Grass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:grass_block", + "unlocalizedName": "block.minecraft.grass_block", + "localizedName": "Grass Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:grass_path", + "unlocalizedName": "block.minecraft.grass_path", + "localizedName": "Grass Path", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gravel", + "unlocalizedName": "block.minecraft.gravel", + "localizedName": "Gravel", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_banner", + "unlocalizedName": "block.minecraft.gray_banner", + "localizedName": "Gray Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_bed", + "unlocalizedName": "block.minecraft.gray_bed", + "localizedName": "Gray Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_carpet", + "unlocalizedName": "block.minecraft.gray_carpet", + "localizedName": "Gray Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_concrete", + "unlocalizedName": "block.minecraft.gray_concrete", + "localizedName": "Gray Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_concrete_powder", + "unlocalizedName": "block.minecraft.gray_concrete_powder", + "localizedName": "Gray Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_dye", + "unlocalizedName": "item.minecraft.gray_dye", + "localizedName": "Gray Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_glazed_terracotta", + "unlocalizedName": "block.minecraft.gray_glazed_terracotta", + "localizedName": "Gray Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_shulker_box", + "unlocalizedName": "block.minecraft.gray_shulker_box", + "localizedName": "Gray Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_stained_glass", + "unlocalizedName": "block.minecraft.gray_stained_glass", + "localizedName": "Gray Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_stained_glass_pane", + "unlocalizedName": "block.minecraft.gray_stained_glass_pane", + "localizedName": "Gray Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_terracotta", + "unlocalizedName": "block.minecraft.gray_terracotta", + "localizedName": "Gray Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gray_wool", + "unlocalizedName": "block.minecraft.gray_wool", + "localizedName": "Gray Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:green_banner", + "unlocalizedName": "block.minecraft.green_banner", + "localizedName": "Green Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:green_bed", + "unlocalizedName": "block.minecraft.green_bed", + "localizedName": "Green Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:green_carpet", + "unlocalizedName": "block.minecraft.green_carpet", + "localizedName": "Green Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:green_concrete", + "unlocalizedName": "block.minecraft.green_concrete", + "localizedName": "Green Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:green_concrete_powder", + "unlocalizedName": "block.minecraft.green_concrete_powder", + "localizedName": "Green Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:green_dye", + "unlocalizedName": "item.minecraft.green_dye", + "localizedName": "Green Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:green_glazed_terracotta", + "unlocalizedName": "block.minecraft.green_glazed_terracotta", + "localizedName": "Green Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:green_shulker_box", + "unlocalizedName": "block.minecraft.green_shulker_box", + "localizedName": "Green Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:green_stained_glass", + "unlocalizedName": "block.minecraft.green_stained_glass", + "localizedName": "Green Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:green_stained_glass_pane", + "unlocalizedName": "block.minecraft.green_stained_glass_pane", + "localizedName": "Green Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:green_terracotta", + "unlocalizedName": "block.minecraft.green_terracotta", + "localizedName": "Green Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:green_wool", + "unlocalizedName": "block.minecraft.green_wool", + "localizedName": "Green Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:grindstone", + "unlocalizedName": "block.minecraft.grindstone", + "localizedName": "Grindstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:guardian_spawn_egg", + "unlocalizedName": "item.minecraft.guardian_spawn_egg", + "localizedName": "Guardian Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:gunpowder", + "unlocalizedName": "item.minecraft.gunpowder", + "localizedName": "Gunpowder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:hay_block", + "unlocalizedName": "block.minecraft.hay_block", + "localizedName": "Hay Bale", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:heart_of_the_sea", + "unlocalizedName": "item.minecraft.heart_of_the_sea", + "localizedName": "Heart of the Sea", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:heavy_weighted_pressure_plate", + "unlocalizedName": "block.minecraft.heavy_weighted_pressure_plate", + "localizedName": "Heavy Weighted Pressure Plate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:hopper", + "unlocalizedName": "block.minecraft.hopper", + "localizedName": "Hopper", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:hopper_minecart", + "unlocalizedName": "item.minecraft.hopper_minecart", + "localizedName": "Minecart with Hopper", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:horn_coral", + "unlocalizedName": "block.minecraft.horn_coral", + "localizedName": "Horn Coral", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:horn_coral_block", + "unlocalizedName": "block.minecraft.horn_coral_block", + "localizedName": "Horn Coral Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:horn_coral_fan", + "unlocalizedName": "block.minecraft.horn_coral_fan", + "localizedName": "Horn Coral Fan", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:horse_spawn_egg", + "unlocalizedName": "item.minecraft.horse_spawn_egg", + "localizedName": "Horse Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:husk_spawn_egg", + "unlocalizedName": "item.minecraft.husk_spawn_egg", + "localizedName": "Husk Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:ice", + "unlocalizedName": "block.minecraft.ice", + "localizedName": "Ice", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:infested_chiseled_stone_bricks", + "unlocalizedName": "block.minecraft.infested_chiseled_stone_bricks", + "localizedName": "Infested Chiseled Stone Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:infested_cobblestone", + "unlocalizedName": "block.minecraft.infested_cobblestone", + "localizedName": "Infested Cobblestone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:infested_cracked_stone_bricks", + "unlocalizedName": "block.minecraft.infested_cracked_stone_bricks", + "localizedName": "Infested Cracked Stone Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:infested_mossy_stone_bricks", + "unlocalizedName": "block.minecraft.infested_mossy_stone_bricks", + "localizedName": "Infested Mossy Stone Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:infested_stone", + "unlocalizedName": "block.minecraft.infested_stone", + "localizedName": "Infested Stone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:infested_stone_bricks", + "unlocalizedName": "block.minecraft.infested_stone_bricks", + "localizedName": "Infested Stone Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:ink_sac", + "unlocalizedName": "item.minecraft.ink_sac", + "localizedName": "Ink Sac", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:iron_axe", + "unlocalizedName": "item.minecraft.iron_axe", + "localizedName": "Iron Axe", + "maxStackSize": 1, + "maxDamage": 250 + }, + { + "id": "minecraft:iron_bars", + "unlocalizedName": "block.minecraft.iron_bars", + "localizedName": "Iron Bars", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:iron_block", + "unlocalizedName": "block.minecraft.iron_block", + "localizedName": "Block of Iron", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:iron_boots", + "unlocalizedName": "item.minecraft.iron_boots", + "localizedName": "Iron Boots", + "maxStackSize": 1, + "maxDamage": 195 + }, + { + "id": "minecraft:iron_chestplate", + "unlocalizedName": "item.minecraft.iron_chestplate", + "localizedName": "Iron Chestplate", + "maxStackSize": 1, + "maxDamage": 240 + }, + { + "id": "minecraft:iron_door", + "unlocalizedName": "block.minecraft.iron_door", + "localizedName": "Iron Door", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:iron_helmet", + "unlocalizedName": "item.minecraft.iron_helmet", + "localizedName": "Iron Helmet", + "maxStackSize": 1, + "maxDamage": 165 + }, + { + "id": "minecraft:iron_hoe", + "unlocalizedName": "item.minecraft.iron_hoe", + "localizedName": "Iron Hoe", + "maxStackSize": 1, + "maxDamage": 250 + }, + { + "id": "minecraft:iron_horse_armor", + "unlocalizedName": "item.minecraft.iron_horse_armor", + "localizedName": "Iron Horse Armor", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:iron_ingot", + "unlocalizedName": "item.minecraft.iron_ingot", + "localizedName": "Iron Ingot", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:iron_leggings", + "unlocalizedName": "item.minecraft.iron_leggings", + "localizedName": "Iron Leggings", + "maxStackSize": 1, + "maxDamage": 225 + }, + { + "id": "minecraft:iron_nugget", + "unlocalizedName": "item.minecraft.iron_nugget", + "localizedName": "Iron Nugget", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:iron_ore", + "unlocalizedName": "block.minecraft.iron_ore", + "localizedName": "Iron Ore", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:iron_pickaxe", + "unlocalizedName": "item.minecraft.iron_pickaxe", + "localizedName": "Iron Pickaxe", + "maxStackSize": 1, + "maxDamage": 250 + }, + { + "id": "minecraft:iron_shovel", + "unlocalizedName": "item.minecraft.iron_shovel", + "localizedName": "Iron Shovel", + "maxStackSize": 1, + "maxDamage": 250 + }, + { + "id": "minecraft:iron_sword", + "unlocalizedName": "item.minecraft.iron_sword", + "localizedName": "Iron Sword", + "maxStackSize": 1, + "maxDamage": 250 + }, + { + "id": "minecraft:iron_trapdoor", + "unlocalizedName": "block.minecraft.iron_trapdoor", + "localizedName": "Iron Trapdoor", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:item_frame", + "unlocalizedName": "item.minecraft.item_frame", + "localizedName": "Item Frame", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jack_o_lantern", + "unlocalizedName": "block.minecraft.jack_o_lantern", + "localizedName": "Jack o\u0027Lantern", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jigsaw", + "unlocalizedName": "block.minecraft.jigsaw", + "localizedName": "Jigsaw Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jukebox", + "unlocalizedName": "block.minecraft.jukebox", + "localizedName": "Jukebox", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_boat", + "unlocalizedName": "item.minecraft.jungle_boat", + "localizedName": "Jungle Boat", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_button", + "unlocalizedName": "block.minecraft.jungle_button", + "localizedName": "Jungle Button", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_door", + "unlocalizedName": "block.minecraft.jungle_door", + "localizedName": "Jungle Door", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_fence", + "unlocalizedName": "block.minecraft.jungle_fence", + "localizedName": "Jungle Fence", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_fence_gate", + "unlocalizedName": "block.minecraft.jungle_fence_gate", + "localizedName": "Jungle Fence Gate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_leaves", + "unlocalizedName": "block.minecraft.jungle_leaves", + "localizedName": "Jungle Leaves", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_log", + "unlocalizedName": "block.minecraft.jungle_log", + "localizedName": "Jungle Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_planks", + "unlocalizedName": "block.minecraft.jungle_planks", + "localizedName": "Jungle Planks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_pressure_plate", + "unlocalizedName": "block.minecraft.jungle_pressure_plate", + "localizedName": "Jungle Pressure Plate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_sapling", + "unlocalizedName": "block.minecraft.jungle_sapling", + "localizedName": "Jungle Sapling", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_sign", + "unlocalizedName": "block.minecraft.jungle_sign", + "localizedName": "Jungle Sign", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_slab", + "unlocalizedName": "block.minecraft.jungle_slab", + "localizedName": "Jungle Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_stairs", + "unlocalizedName": "block.minecraft.jungle_stairs", + "localizedName": "Jungle Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_trapdoor", + "unlocalizedName": "block.minecraft.jungle_trapdoor", + "localizedName": "Jungle Trapdoor", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:jungle_wood", + "unlocalizedName": "block.minecraft.jungle_wood", + "localizedName": "Jungle Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:kelp", + "unlocalizedName": "block.minecraft.kelp", + "localizedName": "Kelp", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:knowledge_book", + "unlocalizedName": "item.minecraft.knowledge_book", + "localizedName": "Knowledge Book", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:ladder", + "unlocalizedName": "block.minecraft.ladder", + "localizedName": "Ladder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lantern", + "unlocalizedName": "block.minecraft.lantern", + "localizedName": "Lantern", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lapis_block", + "unlocalizedName": "block.minecraft.lapis_block", + "localizedName": "Lapis Lazuli Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lapis_lazuli", + "unlocalizedName": "item.minecraft.lapis_lazuli", + "localizedName": "Lapis Lazuli", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lapis_ore", + "unlocalizedName": "block.minecraft.lapis_ore", + "localizedName": "Lapis Lazuli Ore", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:large_fern", + "unlocalizedName": "block.minecraft.large_fern", + "localizedName": "Large Fern", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lava_bucket", + "unlocalizedName": "item.minecraft.lava_bucket", + "localizedName": "Lava Bucket", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:lead", + "unlocalizedName": "item.minecraft.lead", + "localizedName": "Lead", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:leather", + "unlocalizedName": "item.minecraft.leather", + "localizedName": "Leather", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:leather_boots", + "unlocalizedName": "item.minecraft.leather_boots", + "localizedName": "Leather Boots", + "maxStackSize": 1, + "maxDamage": 65 + }, + { + "id": "minecraft:leather_chestplate", + "unlocalizedName": "item.minecraft.leather_chestplate", + "localizedName": "Leather Tunic", + "maxStackSize": 1, + "maxDamage": 80 + }, + { + "id": "minecraft:leather_helmet", + "unlocalizedName": "item.minecraft.leather_helmet", + "localizedName": "Leather Cap", + "maxStackSize": 1, + "maxDamage": 55 + }, + { + "id": "minecraft:leather_horse_armor", + "unlocalizedName": "item.minecraft.leather_horse_armor", + "localizedName": "Leather Horse Armor", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:leather_leggings", + "unlocalizedName": "item.minecraft.leather_leggings", + "localizedName": "Leather Pants", + "maxStackSize": 1, + "maxDamage": 75 + }, + { + "id": "minecraft:lectern", + "unlocalizedName": "block.minecraft.lectern", + "localizedName": "Lectern", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lever", + "unlocalizedName": "block.minecraft.lever", + "localizedName": "Lever", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_banner", + "unlocalizedName": "block.minecraft.light_blue_banner", + "localizedName": "Light Blue Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_bed", + "unlocalizedName": "block.minecraft.light_blue_bed", + "localizedName": "Light Blue Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_carpet", + "unlocalizedName": "block.minecraft.light_blue_carpet", + "localizedName": "Light Blue Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_concrete", + "unlocalizedName": "block.minecraft.light_blue_concrete", + "localizedName": "Light Blue Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_concrete_powder", + "unlocalizedName": "block.minecraft.light_blue_concrete_powder", + "localizedName": "Light Blue Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_dye", + "unlocalizedName": "item.minecraft.light_blue_dye", + "localizedName": "Light Blue Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_glazed_terracotta", + "unlocalizedName": "block.minecraft.light_blue_glazed_terracotta", + "localizedName": "Light Blue Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_shulker_box", + "unlocalizedName": "block.minecraft.light_blue_shulker_box", + "localizedName": "Light Blue Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_stained_glass", + "unlocalizedName": "block.minecraft.light_blue_stained_glass", + "localizedName": "Light Blue Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_stained_glass_pane", + "unlocalizedName": "block.minecraft.light_blue_stained_glass_pane", + "localizedName": "Light Blue Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_terracotta", + "unlocalizedName": "block.minecraft.light_blue_terracotta", + "localizedName": "Light Blue Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_blue_wool", + "unlocalizedName": "block.minecraft.light_blue_wool", + "localizedName": "Light Blue Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_banner", + "unlocalizedName": "block.minecraft.light_gray_banner", + "localizedName": "Light Gray Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_bed", + "unlocalizedName": "block.minecraft.light_gray_bed", + "localizedName": "Light Gray Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_carpet", + "unlocalizedName": "block.minecraft.light_gray_carpet", + "localizedName": "Light Gray Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_concrete", + "unlocalizedName": "block.minecraft.light_gray_concrete", + "localizedName": "Light Gray Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_concrete_powder", + "unlocalizedName": "block.minecraft.light_gray_concrete_powder", + "localizedName": "Light Gray Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_dye", + "unlocalizedName": "item.minecraft.light_gray_dye", + "localizedName": "Light Gray Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_glazed_terracotta", + "unlocalizedName": "block.minecraft.light_gray_glazed_terracotta", + "localizedName": "Light Gray Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_shulker_box", + "unlocalizedName": "block.minecraft.light_gray_shulker_box", + "localizedName": "Light Gray Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_stained_glass", + "unlocalizedName": "block.minecraft.light_gray_stained_glass", + "localizedName": "Light Gray Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_stained_glass_pane", + "unlocalizedName": "block.minecraft.light_gray_stained_glass_pane", + "localizedName": "Light Gray Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_terracotta", + "unlocalizedName": "block.minecraft.light_gray_terracotta", + "localizedName": "Light Gray Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_gray_wool", + "unlocalizedName": "block.minecraft.light_gray_wool", + "localizedName": "Light Gray Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:light_weighted_pressure_plate", + "unlocalizedName": "block.minecraft.light_weighted_pressure_plate", + "localizedName": "Light Weighted Pressure Plate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lilac", + "unlocalizedName": "block.minecraft.lilac", + "localizedName": "Lilac", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lily_of_the_valley", + "unlocalizedName": "block.minecraft.lily_of_the_valley", + "localizedName": "Lily of the Valley", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lily_pad", + "unlocalizedName": "block.minecraft.lily_pad", + "localizedName": "Lily Pad", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_banner", + "unlocalizedName": "block.minecraft.lime_banner", + "localizedName": "Lime Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_bed", + "unlocalizedName": "block.minecraft.lime_bed", + "localizedName": "Lime Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_carpet", + "unlocalizedName": "block.minecraft.lime_carpet", + "localizedName": "Lime Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_concrete", + "unlocalizedName": "block.minecraft.lime_concrete", + "localizedName": "Lime Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_concrete_powder", + "unlocalizedName": "block.minecraft.lime_concrete_powder", + "localizedName": "Lime Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_dye", + "unlocalizedName": "item.minecraft.lime_dye", + "localizedName": "Lime Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_glazed_terracotta", + "unlocalizedName": "block.minecraft.lime_glazed_terracotta", + "localizedName": "Lime Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_shulker_box", + "unlocalizedName": "block.minecraft.lime_shulker_box", + "localizedName": "Lime Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_stained_glass", + "unlocalizedName": "block.minecraft.lime_stained_glass", + "localizedName": "Lime Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_stained_glass_pane", + "unlocalizedName": "block.minecraft.lime_stained_glass_pane", + "localizedName": "Lime Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_terracotta", + "unlocalizedName": "block.minecraft.lime_terracotta", + "localizedName": "Lime Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lime_wool", + "unlocalizedName": "block.minecraft.lime_wool", + "localizedName": "Lime Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:lingering_potion", + "unlocalizedName": "item.minecraft.lingering_potion.effect.water", + "localizedName": "Lingering Water Bottle", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:llama_spawn_egg", + "unlocalizedName": "item.minecraft.llama_spawn_egg", + "localizedName": "Llama Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:loom", + "unlocalizedName": "block.minecraft.loom", + "localizedName": "Loom", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_banner", + "unlocalizedName": "block.minecraft.magenta_banner", + "localizedName": "Magenta Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_bed", + "unlocalizedName": "block.minecraft.magenta_bed", + "localizedName": "Magenta Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_carpet", + "unlocalizedName": "block.minecraft.magenta_carpet", + "localizedName": "Magenta Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_concrete", + "unlocalizedName": "block.minecraft.magenta_concrete", + "localizedName": "Magenta Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_concrete_powder", + "unlocalizedName": "block.minecraft.magenta_concrete_powder", + "localizedName": "Magenta Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_dye", + "unlocalizedName": "item.minecraft.magenta_dye", + "localizedName": "Magenta Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_glazed_terracotta", + "unlocalizedName": "block.minecraft.magenta_glazed_terracotta", + "localizedName": "Magenta Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_shulker_box", + "unlocalizedName": "block.minecraft.magenta_shulker_box", + "localizedName": "Magenta Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_stained_glass", + "unlocalizedName": "block.minecraft.magenta_stained_glass", + "localizedName": "Magenta Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_stained_glass_pane", + "unlocalizedName": "block.minecraft.magenta_stained_glass_pane", + "localizedName": "Magenta Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_terracotta", + "unlocalizedName": "block.minecraft.magenta_terracotta", + "localizedName": "Magenta Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magenta_wool", + "unlocalizedName": "block.minecraft.magenta_wool", + "localizedName": "Magenta Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magma_block", + "unlocalizedName": "block.minecraft.magma_block", + "localizedName": "Magma Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magma_cream", + "unlocalizedName": "item.minecraft.magma_cream", + "localizedName": "Magma Cream", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:magma_cube_spawn_egg", + "unlocalizedName": "item.minecraft.magma_cube_spawn_egg", + "localizedName": "Magma Cube Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:map", + "unlocalizedName": "item.minecraft.map", + "localizedName": "Empty Map", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:melon", + "unlocalizedName": "block.minecraft.melon", + "localizedName": "Melon", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:melon_seeds", + "unlocalizedName": "item.minecraft.melon_seeds", + "localizedName": "Melon Seeds", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:melon_slice", + "unlocalizedName": "item.minecraft.melon_slice", + "localizedName": "Melon Slice", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:milk_bucket", + "unlocalizedName": "item.minecraft.milk_bucket", + "localizedName": "Milk Bucket", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:minecart", + "unlocalizedName": "item.minecraft.minecart", + "localizedName": "Minecart", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:mojang_banner_pattern", + "unlocalizedName": "item.minecraft.mojang_banner_pattern", + "localizedName": "Banner Pattern", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:mooshroom_spawn_egg", + "unlocalizedName": "item.minecraft.mooshroom_spawn_egg", + "localizedName": "Mooshroom Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mossy_cobblestone", + "unlocalizedName": "block.minecraft.mossy_cobblestone", + "localizedName": "Mossy Cobblestone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mossy_cobblestone_slab", + "unlocalizedName": "block.minecraft.mossy_cobblestone_slab", + "localizedName": "Mossy Cobblestone Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mossy_cobblestone_stairs", + "unlocalizedName": "block.minecraft.mossy_cobblestone_stairs", + "localizedName": "Mossy Cobblestone Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mossy_cobblestone_wall", + "unlocalizedName": "block.minecraft.mossy_cobblestone_wall", + "localizedName": "Mossy Cobblestone Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mossy_stone_brick_slab", + "unlocalizedName": "block.minecraft.mossy_stone_brick_slab", + "localizedName": "Mossy Stone Brick Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mossy_stone_brick_stairs", + "unlocalizedName": "block.minecraft.mossy_stone_brick_stairs", + "localizedName": "Mossy Stone Brick Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mossy_stone_brick_wall", + "unlocalizedName": "block.minecraft.mossy_stone_brick_wall", + "localizedName": "Mossy Stone Brick Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mossy_stone_bricks", + "unlocalizedName": "block.minecraft.mossy_stone_bricks", + "localizedName": "Mossy Stone Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mule_spawn_egg", + "unlocalizedName": "item.minecraft.mule_spawn_egg", + "localizedName": "Mule Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mushroom_stem", + "unlocalizedName": "block.minecraft.mushroom_stem", + "localizedName": "Mushroom Stem", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mushroom_stew", + "unlocalizedName": "item.minecraft.mushroom_stew", + "localizedName": "Mushroom Stew", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_11", + "unlocalizedName": "item.minecraft.music_disc_11", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_13", + "unlocalizedName": "item.minecraft.music_disc_13", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_blocks", + "unlocalizedName": "item.minecraft.music_disc_blocks", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_cat", + "unlocalizedName": "item.minecraft.music_disc_cat", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_chirp", + "unlocalizedName": "item.minecraft.music_disc_chirp", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_far", + "unlocalizedName": "item.minecraft.music_disc_far", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_mall", + "unlocalizedName": "item.minecraft.music_disc_mall", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_mellohi", + "unlocalizedName": "item.minecraft.music_disc_mellohi", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_stal", + "unlocalizedName": "item.minecraft.music_disc_stal", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_strad", + "unlocalizedName": "item.minecraft.music_disc_strad", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_wait", + "unlocalizedName": "item.minecraft.music_disc_wait", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:music_disc_ward", + "unlocalizedName": "item.minecraft.music_disc_ward", + "localizedName": "Music Disc", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:mutton", + "unlocalizedName": "item.minecraft.mutton", + "localizedName": "Raw Mutton", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:mycelium", + "unlocalizedName": "block.minecraft.mycelium", + "localizedName": "Mycelium", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:name_tag", + "unlocalizedName": "item.minecraft.name_tag", + "localizedName": "Name Tag", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nautilus_shell", + "unlocalizedName": "item.minecraft.nautilus_shell", + "localizedName": "Nautilus Shell", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nether_brick", + "unlocalizedName": "item.minecraft.nether_brick", + "localizedName": "Nether Brick", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nether_brick_fence", + "unlocalizedName": "block.minecraft.nether_brick_fence", + "localizedName": "Nether Brick Fence", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nether_brick_slab", + "unlocalizedName": "block.minecraft.nether_brick_slab", + "localizedName": "Nether Brick Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nether_brick_stairs", + "unlocalizedName": "block.minecraft.nether_brick_stairs", + "localizedName": "Nether Brick Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nether_brick_wall", + "unlocalizedName": "block.minecraft.nether_brick_wall", + "localizedName": "Nether Brick Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nether_bricks", + "unlocalizedName": "block.minecraft.nether_bricks", + "localizedName": "Nether Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nether_quartz_ore", + "unlocalizedName": "block.minecraft.nether_quartz_ore", + "localizedName": "Nether Quartz Ore", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nether_star", + "unlocalizedName": "item.minecraft.nether_star", + "localizedName": "Nether Star", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nether_wart", + "unlocalizedName": "item.minecraft.nether_wart", + "localizedName": "Nether Wart", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:nether_wart_block", + "unlocalizedName": "block.minecraft.nether_wart_block", + "localizedName": "Nether Wart Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:netherrack", + "unlocalizedName": "block.minecraft.netherrack", + "localizedName": "Netherrack", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:note_block", + "unlocalizedName": "block.minecraft.note_block", + "localizedName": "Note Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_boat", + "unlocalizedName": "item.minecraft.oak_boat", + "localizedName": "Oak Boat", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_button", + "unlocalizedName": "block.minecraft.oak_button", + "localizedName": "Oak Button", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_door", + "unlocalizedName": "block.minecraft.oak_door", + "localizedName": "Oak Door", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_fence", + "unlocalizedName": "block.minecraft.oak_fence", + "localizedName": "Oak Fence", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_fence_gate", + "unlocalizedName": "block.minecraft.oak_fence_gate", + "localizedName": "Oak Fence Gate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_leaves", + "unlocalizedName": "block.minecraft.oak_leaves", + "localizedName": "Oak Leaves", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_log", + "unlocalizedName": "block.minecraft.oak_log", + "localizedName": "Oak Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_planks", + "unlocalizedName": "block.minecraft.oak_planks", + "localizedName": "Oak Planks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_pressure_plate", + "unlocalizedName": "block.minecraft.oak_pressure_plate", + "localizedName": "Oak Pressure Plate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_sapling", + "unlocalizedName": "block.minecraft.oak_sapling", + "localizedName": "Oak Sapling", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_sign", + "unlocalizedName": "block.minecraft.oak_sign", + "localizedName": "Oak Sign", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_slab", + "unlocalizedName": "block.minecraft.oak_slab", + "localizedName": "Oak Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_stairs", + "unlocalizedName": "block.minecraft.oak_stairs", + "localizedName": "Oak Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_trapdoor", + "unlocalizedName": "block.minecraft.oak_trapdoor", + "localizedName": "Oak Trapdoor", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oak_wood", + "unlocalizedName": "block.minecraft.oak_wood", + "localizedName": "Oak Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:observer", + "unlocalizedName": "block.minecraft.observer", + "localizedName": "Observer", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:obsidian", + "unlocalizedName": "block.minecraft.obsidian", + "localizedName": "Obsidian", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:ocelot_spawn_egg", + "unlocalizedName": "item.minecraft.ocelot_spawn_egg", + "localizedName": "Ocelot Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_banner", + "unlocalizedName": "block.minecraft.orange_banner", + "localizedName": "Orange Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_bed", + "unlocalizedName": "block.minecraft.orange_bed", + "localizedName": "Orange Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_carpet", + "unlocalizedName": "block.minecraft.orange_carpet", + "localizedName": "Orange Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_concrete", + "unlocalizedName": "block.minecraft.orange_concrete", + "localizedName": "Orange Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_concrete_powder", + "unlocalizedName": "block.minecraft.orange_concrete_powder", + "localizedName": "Orange Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_dye", + "unlocalizedName": "item.minecraft.orange_dye", + "localizedName": "Orange Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_glazed_terracotta", + "unlocalizedName": "block.minecraft.orange_glazed_terracotta", + "localizedName": "Orange Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_shulker_box", + "unlocalizedName": "block.minecraft.orange_shulker_box", + "localizedName": "Orange Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_stained_glass", + "unlocalizedName": "block.minecraft.orange_stained_glass", + "localizedName": "Orange Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_stained_glass_pane", + "unlocalizedName": "block.minecraft.orange_stained_glass_pane", + "localizedName": "Orange Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_terracotta", + "unlocalizedName": "block.minecraft.orange_terracotta", + "localizedName": "Orange Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_tulip", + "unlocalizedName": "block.minecraft.orange_tulip", + "localizedName": "Orange Tulip", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:orange_wool", + "unlocalizedName": "block.minecraft.orange_wool", + "localizedName": "Orange Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:oxeye_daisy", + "unlocalizedName": "block.minecraft.oxeye_daisy", + "localizedName": "Oxeye Daisy", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:packed_ice", + "unlocalizedName": "block.minecraft.packed_ice", + "localizedName": "Packed Ice", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:painting", + "unlocalizedName": "item.minecraft.painting", + "localizedName": "Painting", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:panda_spawn_egg", + "unlocalizedName": "item.minecraft.panda_spawn_egg", + "localizedName": "Panda Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:paper", + "unlocalizedName": "item.minecraft.paper", + "localizedName": "Paper", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:parrot_spawn_egg", + "unlocalizedName": "item.minecraft.parrot_spawn_egg", + "localizedName": "Parrot Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:peony", + "unlocalizedName": "block.minecraft.peony", + "localizedName": "Peony", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:petrified_oak_slab", + "unlocalizedName": "block.minecraft.petrified_oak_slab", + "localizedName": "Petrified Oak Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:phantom_membrane", + "unlocalizedName": "item.minecraft.phantom_membrane", + "localizedName": "Phantom Membrane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:phantom_spawn_egg", + "unlocalizedName": "item.minecraft.phantom_spawn_egg", + "localizedName": "Phantom Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pig_spawn_egg", + "unlocalizedName": "item.minecraft.pig_spawn_egg", + "localizedName": "Pig Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pillager_spawn_egg", + "unlocalizedName": "item.minecraft.pillager_spawn_egg", + "localizedName": "Pillager Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_banner", + "unlocalizedName": "block.minecraft.pink_banner", + "localizedName": "Pink Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_bed", + "unlocalizedName": "block.minecraft.pink_bed", + "localizedName": "Pink Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_carpet", + "unlocalizedName": "block.minecraft.pink_carpet", + "localizedName": "Pink Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_concrete", + "unlocalizedName": "block.minecraft.pink_concrete", + "localizedName": "Pink Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_concrete_powder", + "unlocalizedName": "block.minecraft.pink_concrete_powder", + "localizedName": "Pink Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_dye", + "unlocalizedName": "item.minecraft.pink_dye", + "localizedName": "Pink Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_glazed_terracotta", + "unlocalizedName": "block.minecraft.pink_glazed_terracotta", + "localizedName": "Pink Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_shulker_box", + "unlocalizedName": "block.minecraft.pink_shulker_box", + "localizedName": "Pink Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_stained_glass", + "unlocalizedName": "block.minecraft.pink_stained_glass", + "localizedName": "Pink Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_stained_glass_pane", + "unlocalizedName": "block.minecraft.pink_stained_glass_pane", + "localizedName": "Pink Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_terracotta", + "unlocalizedName": "block.minecraft.pink_terracotta", + "localizedName": "Pink Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_tulip", + "unlocalizedName": "block.minecraft.pink_tulip", + "localizedName": "Pink Tulip", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pink_wool", + "unlocalizedName": "block.minecraft.pink_wool", + "localizedName": "Pink Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:piston", + "unlocalizedName": "block.minecraft.piston", + "localizedName": "Piston", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:player_head", + "unlocalizedName": "block.minecraft.player_head", + "localizedName": "Player Head", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:podzol", + "unlocalizedName": "block.minecraft.podzol", + "localizedName": "Podzol", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:poisonous_potato", + "unlocalizedName": "item.minecraft.poisonous_potato", + "localizedName": "Poisonous Potato", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:polar_bear_spawn_egg", + "unlocalizedName": "item.minecraft.polar_bear_spawn_egg", + "localizedName": "Polar Bear Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:polished_andesite", + "unlocalizedName": "block.minecraft.polished_andesite", + "localizedName": "Polished Andesite", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:polished_andesite_slab", + "unlocalizedName": "block.minecraft.polished_andesite_slab", + "localizedName": "Polished Andesite Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:polished_andesite_stairs", + "unlocalizedName": "block.minecraft.polished_andesite_stairs", + "localizedName": "Polished Andesite Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:polished_diorite", + "unlocalizedName": "block.minecraft.polished_diorite", + "localizedName": "Polished Diorite", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:polished_diorite_slab", + "unlocalizedName": "block.minecraft.polished_diorite_slab", + "localizedName": "Polished Diorite Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:polished_diorite_stairs", + "unlocalizedName": "block.minecraft.polished_diorite_stairs", + "localizedName": "Polished Diorite Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:polished_granite", + "unlocalizedName": "block.minecraft.polished_granite", + "localizedName": "Polished Granite", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:polished_granite_slab", + "unlocalizedName": "block.minecraft.polished_granite_slab", + "localizedName": "Polished Granite Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:polished_granite_stairs", + "unlocalizedName": "block.minecraft.polished_granite_stairs", + "localizedName": "Polished Granite Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:popped_chorus_fruit", + "unlocalizedName": "item.minecraft.popped_chorus_fruit", + "localizedName": "Popped Chorus Fruit", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:poppy", + "unlocalizedName": "block.minecraft.poppy", + "localizedName": "Poppy", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:porkchop", + "unlocalizedName": "item.minecraft.porkchop", + "localizedName": "Raw Porkchop", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:potato", + "unlocalizedName": "item.minecraft.potato", + "localizedName": "Potato", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:potion", + "unlocalizedName": "item.minecraft.potion.effect.water", + "localizedName": "Water Bottle", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:powered_rail", + "unlocalizedName": "block.minecraft.powered_rail", + "localizedName": "Powered Rail", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:prismarine", + "unlocalizedName": "block.minecraft.prismarine", + "localizedName": "Prismarine", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:prismarine_brick_slab", + "unlocalizedName": "block.minecraft.prismarine_brick_slab", + "localizedName": "Prismarine Brick Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:prismarine_brick_stairs", + "unlocalizedName": "block.minecraft.prismarine_brick_stairs", + "localizedName": "Prismarine Brick Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:prismarine_bricks", + "unlocalizedName": "block.minecraft.prismarine_bricks", + "localizedName": "Prismarine Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:prismarine_crystals", + "unlocalizedName": "item.minecraft.prismarine_crystals", + "localizedName": "Prismarine Crystals", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:prismarine_shard", + "unlocalizedName": "item.minecraft.prismarine_shard", + "localizedName": "Prismarine Shard", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:prismarine_slab", + "unlocalizedName": "block.minecraft.prismarine_slab", + "localizedName": "Prismarine Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:prismarine_stairs", + "unlocalizedName": "block.minecraft.prismarine_stairs", + "localizedName": "Prismarine Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:prismarine_wall", + "unlocalizedName": "block.minecraft.prismarine_wall", + "localizedName": "Prismarine Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pufferfish", + "unlocalizedName": "item.minecraft.pufferfish", + "localizedName": "Pufferfish", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pufferfish_bucket", + "unlocalizedName": "item.minecraft.pufferfish_bucket", + "localizedName": "Bucket of Pufferfish", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:pufferfish_spawn_egg", + "unlocalizedName": "item.minecraft.pufferfish_spawn_egg", + "localizedName": "Pufferfish Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pumpkin", + "unlocalizedName": "block.minecraft.pumpkin", + "localizedName": "Pumpkin", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pumpkin_pie", + "unlocalizedName": "item.minecraft.pumpkin_pie", + "localizedName": "Pumpkin Pie", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:pumpkin_seeds", + "unlocalizedName": "item.minecraft.pumpkin_seeds", + "localizedName": "Pumpkin Seeds", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_banner", + "unlocalizedName": "block.minecraft.purple_banner", + "localizedName": "Purple Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_bed", + "unlocalizedName": "block.minecraft.purple_bed", + "localizedName": "Purple Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_carpet", + "unlocalizedName": "block.minecraft.purple_carpet", + "localizedName": "Purple Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_concrete", + "unlocalizedName": "block.minecraft.purple_concrete", + "localizedName": "Purple Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_concrete_powder", + "unlocalizedName": "block.minecraft.purple_concrete_powder", + "localizedName": "Purple Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_dye", + "unlocalizedName": "item.minecraft.purple_dye", + "localizedName": "Purple Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_glazed_terracotta", + "unlocalizedName": "block.minecraft.purple_glazed_terracotta", + "localizedName": "Purple Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_shulker_box", + "unlocalizedName": "block.minecraft.purple_shulker_box", + "localizedName": "Purple Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_stained_glass", + "unlocalizedName": "block.minecraft.purple_stained_glass", + "localizedName": "Purple Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_stained_glass_pane", + "unlocalizedName": "block.minecraft.purple_stained_glass_pane", + "localizedName": "Purple Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_terracotta", + "unlocalizedName": "block.minecraft.purple_terracotta", + "localizedName": "Purple Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purple_wool", + "unlocalizedName": "block.minecraft.purple_wool", + "localizedName": "Purple Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purpur_block", + "unlocalizedName": "block.minecraft.purpur_block", + "localizedName": "Purpur Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purpur_pillar", + "unlocalizedName": "block.minecraft.purpur_pillar", + "localizedName": "Purpur Pillar", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purpur_slab", + "unlocalizedName": "block.minecraft.purpur_slab", + "localizedName": "Purpur Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:purpur_stairs", + "unlocalizedName": "block.minecraft.purpur_stairs", + "localizedName": "Purpur Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:quartz", + "unlocalizedName": "item.minecraft.quartz", + "localizedName": "Nether Quartz", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:quartz_block", + "unlocalizedName": "block.minecraft.quartz_block", + "localizedName": "Block of Quartz", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:quartz_pillar", + "unlocalizedName": "block.minecraft.quartz_pillar", + "localizedName": "Quartz Pillar", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:quartz_slab", + "unlocalizedName": "block.minecraft.quartz_slab", + "localizedName": "Quartz Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:quartz_stairs", + "unlocalizedName": "block.minecraft.quartz_stairs", + "localizedName": "Quartz Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:rabbit", + "unlocalizedName": "item.minecraft.rabbit", + "localizedName": "Raw Rabbit", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:rabbit_foot", + "unlocalizedName": "item.minecraft.rabbit_foot", + "localizedName": "Rabbit\u0027s Foot", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:rabbit_hide", + "unlocalizedName": "item.minecraft.rabbit_hide", + "localizedName": "Rabbit Hide", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:rabbit_spawn_egg", + "unlocalizedName": "item.minecraft.rabbit_spawn_egg", + "localizedName": "Rabbit Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:rabbit_stew", + "unlocalizedName": "item.minecraft.rabbit_stew", + "localizedName": "Rabbit Stew", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:rail", + "unlocalizedName": "block.minecraft.rail", + "localizedName": "Rail", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:ravager_spawn_egg", + "unlocalizedName": "item.minecraft.ravager_spawn_egg", + "localizedName": "Ravager Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_banner", + "unlocalizedName": "block.minecraft.red_banner", + "localizedName": "Red Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:red_bed", + "unlocalizedName": "block.minecraft.red_bed", + "localizedName": "Red Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:red_carpet", + "unlocalizedName": "block.minecraft.red_carpet", + "localizedName": "Red Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_concrete", + "unlocalizedName": "block.minecraft.red_concrete", + "localizedName": "Red Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_concrete_powder", + "unlocalizedName": "block.minecraft.red_concrete_powder", + "localizedName": "Red Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_dye", + "unlocalizedName": "item.minecraft.red_dye", + "localizedName": "Red Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_glazed_terracotta", + "unlocalizedName": "block.minecraft.red_glazed_terracotta", + "localizedName": "Red Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_mushroom", + "unlocalizedName": "block.minecraft.red_mushroom", + "localizedName": "Red Mushroom", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_mushroom_block", + "unlocalizedName": "block.minecraft.red_mushroom_block", + "localizedName": "Red Mushroom Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_nether_brick_slab", + "unlocalizedName": "block.minecraft.red_nether_brick_slab", + "localizedName": "Red Nether Brick Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_nether_brick_stairs", + "unlocalizedName": "block.minecraft.red_nether_brick_stairs", + "localizedName": "Red Nether Brick Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_nether_brick_wall", + "unlocalizedName": "block.minecraft.red_nether_brick_wall", + "localizedName": "Red Nether Brick Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_nether_bricks", + "unlocalizedName": "block.minecraft.red_nether_bricks", + "localizedName": "Red Nether Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_sand", + "unlocalizedName": "block.minecraft.red_sand", + "localizedName": "Red Sand", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_sandstone", + "unlocalizedName": "block.minecraft.red_sandstone", + "localizedName": "Red Sandstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_sandstone_slab", + "unlocalizedName": "block.minecraft.red_sandstone_slab", + "localizedName": "Red Sandstone Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_sandstone_stairs", + "unlocalizedName": "block.minecraft.red_sandstone_stairs", + "localizedName": "Red Sandstone Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_sandstone_wall", + "unlocalizedName": "block.minecraft.red_sandstone_wall", + "localizedName": "Red Sandstone Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_shulker_box", + "unlocalizedName": "block.minecraft.red_shulker_box", + "localizedName": "Red Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:red_stained_glass", + "unlocalizedName": "block.minecraft.red_stained_glass", + "localizedName": "Red Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_stained_glass_pane", + "unlocalizedName": "block.minecraft.red_stained_glass_pane", + "localizedName": "Red Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_terracotta", + "unlocalizedName": "block.minecraft.red_terracotta", + "localizedName": "Red Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_tulip", + "unlocalizedName": "block.minecraft.red_tulip", + "localizedName": "Red Tulip", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:red_wool", + "unlocalizedName": "block.minecraft.red_wool", + "localizedName": "Red Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:redstone", + "unlocalizedName": "item.minecraft.redstone", + "localizedName": "Redstone Dust", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:redstone_block", + "unlocalizedName": "block.minecraft.redstone_block", + "localizedName": "Block of Redstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:redstone_lamp", + "unlocalizedName": "block.minecraft.redstone_lamp", + "localizedName": "Redstone Lamp", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:redstone_ore", + "unlocalizedName": "block.minecraft.redstone_ore", + "localizedName": "Redstone Ore", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:redstone_torch", + "unlocalizedName": "block.minecraft.redstone_torch", + "localizedName": "Redstone Torch", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:repeater", + "unlocalizedName": "block.minecraft.repeater", + "localizedName": "Redstone Repeater", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:repeating_command_block", + "unlocalizedName": "block.minecraft.repeating_command_block", + "localizedName": "Repeating Command Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:rose_bush", + "unlocalizedName": "block.minecraft.rose_bush", + "localizedName": "Rose Bush", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:rotten_flesh", + "unlocalizedName": "item.minecraft.rotten_flesh", + "localizedName": "Rotten Flesh", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:saddle", + "unlocalizedName": "item.minecraft.saddle", + "localizedName": "Saddle", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:salmon", + "unlocalizedName": "item.minecraft.salmon", + "localizedName": "Raw Salmon", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:salmon_bucket", + "unlocalizedName": "item.minecraft.salmon_bucket", + "localizedName": "Bucket of Salmon", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:salmon_spawn_egg", + "unlocalizedName": "item.minecraft.salmon_spawn_egg", + "localizedName": "Salmon Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sand", + "unlocalizedName": "block.minecraft.sand", + "localizedName": "Sand", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sandstone", + "unlocalizedName": "block.minecraft.sandstone", + "localizedName": "Sandstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sandstone_slab", + "unlocalizedName": "block.minecraft.sandstone_slab", + "localizedName": "Sandstone Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sandstone_stairs", + "unlocalizedName": "block.minecraft.sandstone_stairs", + "localizedName": "Sandstone Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sandstone_wall", + "unlocalizedName": "block.minecraft.sandstone_wall", + "localizedName": "Sandstone Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:scaffolding", + "unlocalizedName": "block.minecraft.scaffolding", + "localizedName": "Scaffolding", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:scute", + "unlocalizedName": "item.minecraft.scute", + "localizedName": "Scute", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sea_lantern", + "unlocalizedName": "block.minecraft.sea_lantern", + "localizedName": "Sea Lantern", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sea_pickle", + "unlocalizedName": "block.minecraft.sea_pickle", + "localizedName": "Sea Pickle", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:seagrass", + "unlocalizedName": "block.minecraft.seagrass", + "localizedName": "Seagrass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:shears", + "unlocalizedName": "item.minecraft.shears", + "localizedName": "Shears", + "maxStackSize": 1, + "maxDamage": 238 + }, + { + "id": "minecraft:sheep_spawn_egg", + "unlocalizedName": "item.minecraft.sheep_spawn_egg", + "localizedName": "Sheep Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:shield", + "unlocalizedName": "item.minecraft.shield", + "localizedName": "Shield", + "maxStackSize": 1, + "maxDamage": 336 + }, + { + "id": "minecraft:shulker_box", + "unlocalizedName": "block.minecraft.shulker_box", + "localizedName": "Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:shulker_shell", + "unlocalizedName": "item.minecraft.shulker_shell", + "localizedName": "Shulker Shell", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:shulker_spawn_egg", + "unlocalizedName": "item.minecraft.shulker_spawn_egg", + "localizedName": "Shulker Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:silverfish_spawn_egg", + "unlocalizedName": "item.minecraft.silverfish_spawn_egg", + "localizedName": "Silverfish Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:skeleton_horse_spawn_egg", + "unlocalizedName": "item.minecraft.skeleton_horse_spawn_egg", + "localizedName": "Skeleton Horse Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:skeleton_skull", + "unlocalizedName": "block.minecraft.skeleton_skull", + "localizedName": "Skeleton Skull", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:skeleton_spawn_egg", + "unlocalizedName": "item.minecraft.skeleton_spawn_egg", + "localizedName": "Skeleton Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:skull_banner_pattern", + "unlocalizedName": "item.minecraft.skull_banner_pattern", + "localizedName": "Banner Pattern", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:slime_ball", + "unlocalizedName": "item.minecraft.slime_ball", + "localizedName": "Slimeball", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:slime_block", + "unlocalizedName": "block.minecraft.slime_block", + "localizedName": "Slime Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:slime_spawn_egg", + "unlocalizedName": "item.minecraft.slime_spawn_egg", + "localizedName": "Slime Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smithing_table", + "unlocalizedName": "block.minecraft.smithing_table", + "localizedName": "Smithing Table", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smoker", + "unlocalizedName": "block.minecraft.smoker", + "localizedName": "Smoker", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_quartz", + "unlocalizedName": "block.minecraft.smooth_quartz", + "localizedName": "Smooth Quartz", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_quartz_slab", + "unlocalizedName": "block.minecraft.smooth_quartz_slab", + "localizedName": "Smooth Quartz Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_quartz_stairs", + "unlocalizedName": "block.minecraft.smooth_quartz_stairs", + "localizedName": "Smooth Quartz Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_red_sandstone", + "unlocalizedName": "block.minecraft.smooth_red_sandstone", + "localizedName": "Smooth Red Sandstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_red_sandstone_slab", + "unlocalizedName": "block.minecraft.smooth_red_sandstone_slab", + "localizedName": "Smooth Red Sandstone Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_red_sandstone_stairs", + "unlocalizedName": "block.minecraft.smooth_red_sandstone_stairs", + "localizedName": "Smooth Red Sandstone Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_sandstone", + "unlocalizedName": "block.minecraft.smooth_sandstone", + "localizedName": "Smooth Sandstone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_sandstone_slab", + "unlocalizedName": "block.minecraft.smooth_sandstone_slab", + "localizedName": "Smooth Sandstone Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_sandstone_stairs", + "unlocalizedName": "block.minecraft.smooth_sandstone_stairs", + "localizedName": "Smooth Sandstone Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_stone", + "unlocalizedName": "block.minecraft.smooth_stone", + "localizedName": "Smooth Stone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:smooth_stone_slab", + "unlocalizedName": "block.minecraft.smooth_stone_slab", + "localizedName": "Smooth Stone Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:snow", + "unlocalizedName": "block.minecraft.snow", + "localizedName": "Snow", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:snow_block", + "unlocalizedName": "block.minecraft.snow_block", + "localizedName": "Snow Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:snowball", + "unlocalizedName": "item.minecraft.snowball", + "localizedName": "Snowball", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:soul_sand", + "unlocalizedName": "block.minecraft.soul_sand", + "localizedName": "Soul Sand", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spawner", + "unlocalizedName": "block.minecraft.spawner", + "localizedName": "Spawner", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spectral_arrow", + "unlocalizedName": "item.minecraft.spectral_arrow", + "localizedName": "Spectral Arrow", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spider_eye", + "unlocalizedName": "item.minecraft.spider_eye", + "localizedName": "Spider Eye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spider_spawn_egg", + "unlocalizedName": "item.minecraft.spider_spawn_egg", + "localizedName": "Spider Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:splash_potion", + "unlocalizedName": "item.minecraft.splash_potion.effect.water", + "localizedName": "Splash Water Bottle", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:sponge", + "unlocalizedName": "block.minecraft.sponge", + "localizedName": "Sponge", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_boat", + "unlocalizedName": "item.minecraft.spruce_boat", + "localizedName": "Spruce Boat", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_button", + "unlocalizedName": "block.minecraft.spruce_button", + "localizedName": "Spruce Button", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_door", + "unlocalizedName": "block.minecraft.spruce_door", + "localizedName": "Spruce Door", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_fence", + "unlocalizedName": "block.minecraft.spruce_fence", + "localizedName": "Spruce Fence", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_fence_gate", + "unlocalizedName": "block.minecraft.spruce_fence_gate", + "localizedName": "Spruce Fence Gate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_leaves", + "unlocalizedName": "block.minecraft.spruce_leaves", + "localizedName": "Spruce Leaves", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_log", + "unlocalizedName": "block.minecraft.spruce_log", + "localizedName": "Spruce Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_planks", + "unlocalizedName": "block.minecraft.spruce_planks", + "localizedName": "Spruce Planks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_pressure_plate", + "unlocalizedName": "block.minecraft.spruce_pressure_plate", + "localizedName": "Spruce Pressure Plate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_sapling", + "unlocalizedName": "block.minecraft.spruce_sapling", + "localizedName": "Spruce Sapling", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_sign", + "unlocalizedName": "block.minecraft.spruce_sign", + "localizedName": "Spruce Sign", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_slab", + "unlocalizedName": "block.minecraft.spruce_slab", + "localizedName": "Spruce Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_stairs", + "unlocalizedName": "block.minecraft.spruce_stairs", + "localizedName": "Spruce Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_trapdoor", + "unlocalizedName": "block.minecraft.spruce_trapdoor", + "localizedName": "Spruce Trapdoor", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:spruce_wood", + "unlocalizedName": "block.minecraft.spruce_wood", + "localizedName": "Spruce Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:squid_spawn_egg", + "unlocalizedName": "item.minecraft.squid_spawn_egg", + "localizedName": "Squid Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stick", + "unlocalizedName": "item.minecraft.stick", + "localizedName": "Stick", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sticky_piston", + "unlocalizedName": "block.minecraft.sticky_piston", + "localizedName": "Sticky Piston", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stone", + "unlocalizedName": "block.minecraft.stone", + "localizedName": "Stone", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stone_axe", + "unlocalizedName": "item.minecraft.stone_axe", + "localizedName": "Stone Axe", + "maxStackSize": 1, + "maxDamage": 131 + }, + { + "id": "minecraft:stone_brick_slab", + "unlocalizedName": "block.minecraft.stone_brick_slab", + "localizedName": "Stone Brick Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stone_brick_stairs", + "unlocalizedName": "block.minecraft.stone_brick_stairs", + "localizedName": "Stone Brick Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stone_brick_wall", + "unlocalizedName": "block.minecraft.stone_brick_wall", + "localizedName": "Stone Brick Wall", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stone_bricks", + "unlocalizedName": "block.minecraft.stone_bricks", + "localizedName": "Stone Bricks", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stone_button", + "unlocalizedName": "block.minecraft.stone_button", + "localizedName": "Stone Button", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stone_hoe", + "unlocalizedName": "item.minecraft.stone_hoe", + "localizedName": "Stone Hoe", + "maxStackSize": 1, + "maxDamage": 131 + }, + { + "id": "minecraft:stone_pickaxe", + "unlocalizedName": "item.minecraft.stone_pickaxe", + "localizedName": "Stone Pickaxe", + "maxStackSize": 1, + "maxDamage": 131 + }, + { + "id": "minecraft:stone_pressure_plate", + "unlocalizedName": "block.minecraft.stone_pressure_plate", + "localizedName": "Stone Pressure Plate", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stone_shovel", + "unlocalizedName": "item.minecraft.stone_shovel", + "localizedName": "Stone Shovel", + "maxStackSize": 1, + "maxDamage": 131 + }, + { + "id": "minecraft:stone_slab", + "unlocalizedName": "block.minecraft.stone_slab", + "localizedName": "Stone Slab", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stone_stairs", + "unlocalizedName": "block.minecraft.stone_stairs", + "localizedName": "Stone Stairs", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stone_sword", + "unlocalizedName": "item.minecraft.stone_sword", + "localizedName": "Stone Sword", + "maxStackSize": 1, + "maxDamage": 131 + }, + { + "id": "minecraft:stonecutter", + "unlocalizedName": "block.minecraft.stonecutter", + "localizedName": "Stonecutter", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stray_spawn_egg", + "unlocalizedName": "item.minecraft.stray_spawn_egg", + "localizedName": "Stray Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:string", + "unlocalizedName": "item.minecraft.string", + "localizedName": "String", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_acacia_log", + "unlocalizedName": "block.minecraft.stripped_acacia_log", + "localizedName": "Stripped Acacia Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_acacia_wood", + "unlocalizedName": "block.minecraft.stripped_acacia_wood", + "localizedName": "Stripped Acacia Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_birch_log", + "unlocalizedName": "block.minecraft.stripped_birch_log", + "localizedName": "Stripped Birch Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_birch_wood", + "unlocalizedName": "block.minecraft.stripped_birch_wood", + "localizedName": "Stripped Birch Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_dark_oak_log", + "unlocalizedName": "block.minecraft.stripped_dark_oak_log", + "localizedName": "Stripped Dark Oak Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_dark_oak_wood", + "unlocalizedName": "block.minecraft.stripped_dark_oak_wood", + "localizedName": "Stripped Dark Oak Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_jungle_log", + "unlocalizedName": "block.minecraft.stripped_jungle_log", + "localizedName": "Stripped Jungle Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_jungle_wood", + "unlocalizedName": "block.minecraft.stripped_jungle_wood", + "localizedName": "Stripped Jungle Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_oak_log", + "unlocalizedName": "block.minecraft.stripped_oak_log", + "localizedName": "Stripped Oak Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_oak_wood", + "unlocalizedName": "block.minecraft.stripped_oak_wood", + "localizedName": "Stripped Oak Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_spruce_log", + "unlocalizedName": "block.minecraft.stripped_spruce_log", + "localizedName": "Stripped Spruce Log", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:stripped_spruce_wood", + "unlocalizedName": "block.minecraft.stripped_spruce_wood", + "localizedName": "Stripped Spruce Wood", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:structure_block", + "unlocalizedName": "block.minecraft.structure_block", + "localizedName": "Structure Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:structure_void", + "unlocalizedName": "block.minecraft.structure_void", + "localizedName": "Structure Void", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sugar", + "unlocalizedName": "item.minecraft.sugar", + "localizedName": "Sugar", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sugar_cane", + "unlocalizedName": "block.minecraft.sugar_cane", + "localizedName": "Sugar Cane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:sunflower", + "unlocalizedName": "block.minecraft.sunflower", + "localizedName": "Sunflower", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:suspicious_stew", + "unlocalizedName": "item.minecraft.suspicious_stew", + "localizedName": "Suspicious Stew", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:sweet_berries", + "unlocalizedName": "item.minecraft.sweet_berries", + "localizedName": "Sweet Berries", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:tall_grass", + "unlocalizedName": "block.minecraft.tall_grass", + "localizedName": "Tall Grass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:terracotta", + "unlocalizedName": "block.minecraft.terracotta", + "localizedName": "Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:tipped_arrow", + "unlocalizedName": "item.minecraft.tipped_arrow.effect.poison", + "localizedName": "Arrow of Poison", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:tnt", + "unlocalizedName": "block.minecraft.tnt", + "localizedName": "TNT", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:tnt_minecart", + "unlocalizedName": "item.minecraft.tnt_minecart", + "localizedName": "Minecart with TNT", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:torch", + "unlocalizedName": "block.minecraft.torch", + "localizedName": "Torch", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:totem_of_undying", + "unlocalizedName": "item.minecraft.totem_of_undying", + "localizedName": "Totem of Undying", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:trader_llama_spawn_egg", + "unlocalizedName": "item.minecraft.trader_llama_spawn_egg", + "localizedName": "Trader Llama Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:trapped_chest", + "unlocalizedName": "block.minecraft.trapped_chest", + "localizedName": "Trapped Chest", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:trident", + "unlocalizedName": "item.minecraft.trident", + "localizedName": "Trident", + "maxStackSize": 1, + "maxDamage": 250 + }, + { + "id": "minecraft:tripwire_hook", + "unlocalizedName": "block.minecraft.tripwire_hook", + "localizedName": "Tripwire Hook", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:tropical_fish", + "unlocalizedName": "item.minecraft.tropical_fish", + "localizedName": "Tropical Fish", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:tropical_fish_bucket", + "unlocalizedName": "item.minecraft.tropical_fish_bucket", + "localizedName": "Bucket of Tropical Fish", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:tropical_fish_spawn_egg", + "unlocalizedName": "item.minecraft.tropical_fish_spawn_egg", + "localizedName": "Tropical Fish Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:tube_coral", + "unlocalizedName": "block.minecraft.tube_coral", + "localizedName": "Tube Coral", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:tube_coral_block", + "unlocalizedName": "block.minecraft.tube_coral_block", + "localizedName": "Tube Coral Block", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:tube_coral_fan", + "unlocalizedName": "block.minecraft.tube_coral_fan", + "localizedName": "Tube Coral Fan", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:turtle_egg", + "unlocalizedName": "block.minecraft.turtle_egg", + "localizedName": "Turtle Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:turtle_helmet", + "unlocalizedName": "item.minecraft.turtle_helmet", + "localizedName": "Turtle Shell", + "maxStackSize": 1, + "maxDamage": 275 + }, + { + "id": "minecraft:turtle_spawn_egg", + "unlocalizedName": "item.minecraft.turtle_spawn_egg", + "localizedName": "Turtle Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:vex_spawn_egg", + "unlocalizedName": "item.minecraft.vex_spawn_egg", + "localizedName": "Vex Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:villager_spawn_egg", + "unlocalizedName": "item.minecraft.villager_spawn_egg", + "localizedName": "Villager Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:vindicator_spawn_egg", + "unlocalizedName": "item.minecraft.vindicator_spawn_egg", + "localizedName": "Vindicator Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:vine", + "unlocalizedName": "block.minecraft.vine", + "localizedName": "Vines", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:wandering_trader_spawn_egg", + "unlocalizedName": "item.minecraft.wandering_trader_spawn_egg", + "localizedName": "Wandering Trader Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:water_bucket", + "unlocalizedName": "item.minecraft.water_bucket", + "localizedName": "Water Bucket", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:wet_sponge", + "unlocalizedName": "block.minecraft.wet_sponge", + "localizedName": "Wet Sponge", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:wheat", + "unlocalizedName": "item.minecraft.wheat", + "localizedName": "Wheat", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:wheat_seeds", + "unlocalizedName": "item.minecraft.wheat_seeds", + "localizedName": "Wheat Seeds", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:white_banner", + "unlocalizedName": "block.minecraft.white_banner", + "localizedName": "White Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:white_bed", + "unlocalizedName": "block.minecraft.white_bed", + "localizedName": "White Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:white_carpet", + "unlocalizedName": "block.minecraft.white_carpet", + "localizedName": "White Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:white_concrete", + "unlocalizedName": "block.minecraft.white_concrete", + "localizedName": "White Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:white_concrete_powder", + "unlocalizedName": "block.minecraft.white_concrete_powder", + "localizedName": "White Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:white_dye", + "unlocalizedName": "item.minecraft.white_dye", + "localizedName": "White Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:white_glazed_terracotta", + "unlocalizedName": "block.minecraft.white_glazed_terracotta", + "localizedName": "White Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:white_shulker_box", + "unlocalizedName": "block.minecraft.white_shulker_box", + "localizedName": "White Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:white_stained_glass", + "unlocalizedName": "block.minecraft.white_stained_glass", + "localizedName": "White Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:white_stained_glass_pane", + "unlocalizedName": "block.minecraft.white_stained_glass_pane", + "localizedName": "White Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:white_terracotta", + "unlocalizedName": "block.minecraft.white_terracotta", + "localizedName": "White Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:white_tulip", + "unlocalizedName": "block.minecraft.white_tulip", + "localizedName": "White Tulip", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:white_wool", + "unlocalizedName": "block.minecraft.white_wool", + "localizedName": "White Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:witch_spawn_egg", + "unlocalizedName": "item.minecraft.witch_spawn_egg", + "localizedName": "Witch Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:wither_rose", + "unlocalizedName": "block.minecraft.wither_rose", + "localizedName": "Wither Rose", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:wither_skeleton_skull", + "unlocalizedName": "block.minecraft.wither_skeleton_skull", + "localizedName": "Wither Skeleton Skull", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:wither_skeleton_spawn_egg", + "unlocalizedName": "item.minecraft.wither_skeleton_spawn_egg", + "localizedName": "Wither Skeleton Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:wolf_spawn_egg", + "unlocalizedName": "item.minecraft.wolf_spawn_egg", + "localizedName": "Wolf Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:wooden_axe", + "unlocalizedName": "item.minecraft.wooden_axe", + "localizedName": "Wooden Axe", + "maxStackSize": 1, + "maxDamage": 59 + }, + { + "id": "minecraft:wooden_hoe", + "unlocalizedName": "item.minecraft.wooden_hoe", + "localizedName": "Wooden Hoe", + "maxStackSize": 1, + "maxDamage": 59 + }, + { + "id": "minecraft:wooden_pickaxe", + "unlocalizedName": "item.minecraft.wooden_pickaxe", + "localizedName": "Wooden Pickaxe", + "maxStackSize": 1, + "maxDamage": 59 + }, + { + "id": "minecraft:wooden_shovel", + "unlocalizedName": "item.minecraft.wooden_shovel", + "localizedName": "Wooden Shovel", + "maxStackSize": 1, + "maxDamage": 59 + }, + { + "id": "minecraft:wooden_sword", + "unlocalizedName": "item.minecraft.wooden_sword", + "localizedName": "Wooden Sword", + "maxStackSize": 1, + "maxDamage": 59 + }, + { + "id": "minecraft:writable_book", + "unlocalizedName": "item.minecraft.writable_book", + "localizedName": "Book and Quill", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:written_book", + "unlocalizedName": "item.minecraft.written_book", + "localizedName": "Written Book", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_banner", + "unlocalizedName": "block.minecraft.yellow_banner", + "localizedName": "Yellow Banner", + "maxStackSize": 16, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_bed", + "unlocalizedName": "block.minecraft.yellow_bed", + "localizedName": "Yellow Bed", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_carpet", + "unlocalizedName": "block.minecraft.yellow_carpet", + "localizedName": "Yellow Carpet", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_concrete", + "unlocalizedName": "block.minecraft.yellow_concrete", + "localizedName": "Yellow Concrete", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_concrete_powder", + "unlocalizedName": "block.minecraft.yellow_concrete_powder", + "localizedName": "Yellow Concrete Powder", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_dye", + "unlocalizedName": "item.minecraft.yellow_dye", + "localizedName": "Yellow Dye", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_glazed_terracotta", + "unlocalizedName": "block.minecraft.yellow_glazed_terracotta", + "localizedName": "Yellow Glazed Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_shulker_box", + "unlocalizedName": "block.minecraft.yellow_shulker_box", + "localizedName": "Yellow Shulker Box", + "maxStackSize": 1, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_stained_glass", + "unlocalizedName": "block.minecraft.yellow_stained_glass", + "localizedName": "Yellow Stained Glass", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_stained_glass_pane", + "unlocalizedName": "block.minecraft.yellow_stained_glass_pane", + "localizedName": "Yellow Stained Glass Pane", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_terracotta", + "unlocalizedName": "block.minecraft.yellow_terracotta", + "localizedName": "Yellow Terracotta", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:yellow_wool", + "unlocalizedName": "block.minecraft.yellow_wool", + "localizedName": "Yellow Wool", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:zombie_head", + "unlocalizedName": "block.minecraft.zombie_head", + "localizedName": "Zombie Head", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:zombie_horse_spawn_egg", + "unlocalizedName": "item.minecraft.zombie_horse_spawn_egg", + "localizedName": "Zombie Horse Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:zombie_pigman_spawn_egg", + "unlocalizedName": "item.minecraft.zombie_pigman_spawn_egg", + "localizedName": "Zombie Pigman Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:zombie_spawn_egg", + "unlocalizedName": "item.minecraft.zombie_spawn_egg", + "localizedName": "Zombie Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + }, + { + "id": "minecraft:zombie_villager_spawn_egg", + "unlocalizedName": "item.minecraft.zombie_villager_spawn_egg", + "localizedName": "Zombie Villager Spawn Egg", + "maxStackSize": 64, + "maxDamage": 0 + } +] \ No newline at end of file From 255f016df35bbbc75240d65ad6080a31a9d88554 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 26 Jun 2019 19:44:42 -0700 Subject: [PATCH 220/366] [Forge] Update to 1.14.3 --- worldedit-forge/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 7696d677a..0cddf21e5 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -14,8 +14,8 @@ buildscript { apply plugin: 'eclipse' apply plugin: 'net.minecraftforge.gradle' -def minecraftVersion = "1.14.2" -def forgeVersion = "26.0.48" +def minecraftVersion = "1.14.3" +def forgeVersion = "27.0.13" configurations.all { Configuration it -> it.resolutionStrategy { ResolutionStrategy rs -> @@ -36,7 +36,7 @@ sourceCompatibility = 1.8 targetCompatibility = 1.8 minecraft { - mappings channel: 'snapshot', version: "20190621-${minecraftVersion}" + mappings channel: 'snapshot', version: "20190626-${minecraftVersion}" runs { client = { From 7d558ccffab83618842d7ca57e0267e3aa83a94e Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 26 Jun 2019 23:16:00 -0400 Subject: [PATCH 221/366] Update Piston for to 0.4.2 for bugfix. --- worldedit-libs/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index 76bd162f9..fa57aa1d0 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -91,7 +91,7 @@ configure(subprojects + project("core:ap")) { def textExtrasVersion = "3.0.2" project("core") { def textVersion = "3.0.1" - def pistonVersion = '0.4.1' + def pistonVersion = '0.4.2' dependencies { shade "net.kyori:text-api:$textVersion" From aa8d34c913405242119ca46a7b611388eb62e070 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Thu, 27 Jun 2019 22:25:02 +1000 Subject: [PATCH 222/366] feature(fabric): added fabric support (#491) * Initial work towards Fabric compat. This does not compile yet * Further updates - should compile but Gradle is being weird. * Remove useless buildscript extras * Added mixins to buildscript classpath to fix Loom crash * Make it compile * Got it building and added interaction * Fixed review comments * Use ServerPlayerEntity for FakePlayer * Use method references for nicer names * Fixed remaining comments and added networking for CUI * Output as dist.jar * Added mixins for left click air * Use regex for cleanliness --- build.gradle | 8 +- config/checkstyle/import-control.xml | 12 + settings.gradle | 2 +- worldedit-fabric/build.gradle | 105 + .../worldedit/fabric/CommandWrapper.java | 128 + .../sk89q/worldedit/fabric/FabricAdapter.java | 241 ++ .../worldedit/fabric/FabricBiomeRegistry.java | 58 + .../fabric/FabricBlockCategoryRegistry.java | 46 + .../worldedit/fabric/FabricBlockMaterial.java | 93 + .../worldedit/fabric/FabricBlockRegistry.java | 80 + .../worldedit/fabric/FabricConfiguration.java | 45 + .../worldedit/fabric/FabricDataFixer.java | 2728 +++++++++++++++++ .../sk89q/worldedit/fabric/FabricEntity.java | 116 + .../fabric/FabricEntityProperties.java | 151 + .../fabric/FabricItemCategoryRegistry.java | 46 + .../worldedit/fabric/FabricItemRegistry.java | 42 + .../fabric/FabricPermissionsProvider.java | 50 + .../worldedit/fabric/FabricPlatform.java | 202 ++ .../sk89q/worldedit/fabric/FabricPlayer.java | 267 ++ .../worldedit/fabric/FabricRegistries.java | 75 + .../sk89q/worldedit/fabric/FabricWorld.java | 597 ++++ .../worldedit/fabric/FabricWorldEdit.java | 326 ++ .../sk89q/worldedit/fabric/NBTConverter.java | 252 ++ .../worldedit/fabric/PropertyAdapter.java | 70 + .../worldedit/fabric/ThreadSafeCache.java | 76 + .../worldedit/fabric/TileEntityUtils.java | 79 + .../worldedit/fabric/WorldEditFakePlayer.java | 73 + .../fabric/mixin/MixinServerPlayerEntity.java | 45 + .../net/handler/WECUIPacketHandler.java | 61 + .../main/resources/assets/worldedit/icon.png | Bin 0 -> 5636 bytes .../resources/defaults/worldedit.properties | 33 + .../src/main/resources/fabric.mod.json | 37 + .../src/main/resources/pack.mcmeta | 6 + .../src/main/resources/worldedit.mixins.json | 13 + .../sk89q/worldedit/forge/ForgePlayer.java | 2 +- 35 files changed, 6159 insertions(+), 6 deletions(-) create mode 100644 worldedit-fabric/build.gradle create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/CommandWrapper.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricAdapter.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBiomeRegistry.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockCategoryRegistry.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockMaterial.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockRegistry.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricConfiguration.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricDataFixer.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricEntity.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricEntityProperties.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemCategoryRegistry.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemRegistry.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPermissionsProvider.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricRegistries.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorldEdit.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/NBTConverter.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/PropertyAdapter.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/ThreadSafeCache.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/WorldEditFakePlayer.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinServerPlayerEntity.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/net/handler/WECUIPacketHandler.java create mode 100644 worldedit-fabric/src/main/resources/assets/worldedit/icon.png create mode 100644 worldedit-fabric/src/main/resources/defaults/worldedit.properties create mode 100644 worldedit-fabric/src/main/resources/fabric.mod.json create mode 100644 worldedit-fabric/src/main/resources/pack.mcmeta create mode 100644 worldedit-fabric/src/main/resources/worldedit.mixins.json diff --git a/build.gradle b/build.gradle index 80c9e31f2..dddd5470e 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ println """ 1) Read COMPILING.md if you haven't yet 2) Try running 'build' in a separate Gradle run 3) Use gradlew and not gradle - 4) If you still need help, ask on IRC! irc.esper.net #sk89q + 4) If you still need help, ask on Discord! https://discord.gg/enginehub Output files will be in [subproject]/build/libs ******************************************* @@ -85,7 +85,7 @@ subprojects { } } -configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) { +configure(['core', 'bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) { apply plugin: 'java' apply plugin: 'maven' apply plugin: 'checkstyle' @@ -118,7 +118,7 @@ configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$i archives javadocJar } - if (!(name.equals('worldedit-forge') || name.equals('worldedit-sponge'))) { + if (name == "worldedit-core" || name == "worldedit-bukkit") { task sourcesJar(type: Jar, dependsOn: classes) { classifier = 'sources' from sourceSets.main.allSource @@ -144,7 +144,7 @@ configure(['core', 'bukkit', 'forge', 'sponge'].collect { project(":worldedit-$i } } -configure(['bukkit', 'forge', 'sponge'].collect { project(":worldedit-$it") }) { +configure(['bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) { shadowJar { classifier 'dist' dependencies { diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index a291b5ad5..27b054a03 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -60,6 +60,18 @@ + + + + + + + + + + + + diff --git a/settings.gradle b/settings.gradle index dec0467a5..a7c14e8ee 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,7 @@ rootProject.name = 'worldedit' include 'worldedit-libs' -['bukkit', 'core', 'forge', 'sponge'].forEach { +['bukkit', 'core', 'forge', 'sponge', 'fabric'].forEach { include "worldedit-libs:$it" include "worldedit-$it" } diff --git a/worldedit-fabric/build.gradle b/worldedit-fabric/build.gradle new file mode 100644 index 000000000..6045e3679 --- /dev/null +++ b/worldedit-fabric/build.gradle @@ -0,0 +1,105 @@ +import net.fabricmc.loom.task.RemapJarTask + +buildscript { + repositories { + jcenter() + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + maven { + name = 'sponge' + url = 'https://repo.spongepowered.org/maven' + } + } + + dependencies { + classpath 'net.fabricmc:fabric-loom:0.2.4-SNAPSHOT' + classpath 'org.spongepowered:mixin:0.7.11-SNAPSHOT' + } +} + +apply plugin: 'eclipse' +apply plugin: 'fabric-loom' + +def minecraftVersion = "1.14.2" +def fabricVersion = "0.3.0+build.185" +def yarnMappings = "1.14.2+build.7" +def loaderVersion = "0.4.8+build.155" + +configurations.all { Configuration it -> + it.resolutionStrategy { ResolutionStrategy rs -> + rs.force("com.google.guava:guava:21.0") + } +} + +dependencies { + compile project(':worldedit-core') + compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' + + minecraft "com.mojang:minecraft:${minecraftVersion}" + mappings "net.fabricmc:yarn:${yarnMappings}" + modCompile "net.fabricmc:fabric-loader:${loaderVersion}" + + modCompile "net.fabricmc.fabric-api:fabric-api:${fabricVersion}" + + testCompile group: 'org.mockito', name: 'mockito-core', version: '1.9.0-rc1' +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +minecraft { +} + +project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}" + +processResources { + // this will ensure that this task is redone when the versions change. + inputs.property 'version', project.internalVersion + + from(sourceSets.main.resources.srcDirs) { + include "fabric.mod.json" + expand "version": project.internalVersion + } + + // copy everything else except the mod json + from(sourceSets.main.resources.srcDirs) { + exclude "fabric.mod.json" + } +} + +jar { + manifest { + attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", + "WorldEdit-Version": version) + } +} + +shadowJar { + classifier = 'dist-dev' + dependencies { + relocate "org.slf4j", "com.sk89q.worldedit.slf4j" + relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge" + + include(dependency('org.slf4j:slf4j-api')) + include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + } +} + +task deobfJar(type: Jar) { + from sourceSets.main.output + classifier = 'dev' +} + +artifacts { + archives deobfJar +} + +task shadowJarRemap(type: RemapJarTask) { + input shadowJar.archivePath + output new File(shadowJar.archivePath.getAbsolutePath().replaceFirst('-dev\\.jar$', ".jar")) +} + +shadowJarRemap.dependsOn(shadowJar) +build.dependsOn(shadowJarRemap) \ No newline at end of file diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/CommandWrapper.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/CommandWrapper.java new file mode 100644 index 000000000..8efa5ce97 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/CommandWrapper.java @@ -0,0 +1,128 @@ +/* + * 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.fabric; + +import static com.sk89q.worldedit.fabric.FabricAdapter.adaptPlayer; +import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; + +import com.google.common.collect.ImmutableList; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.context.StringRange; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestion; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.util.Substring; +import net.minecraft.entity.Entity; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import org.enginehub.piston.inject.InjectedValueStore; +import org.enginehub.piston.inject.Key; +import org.enginehub.piston.inject.MapBackedValueStore; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; + + +public final class CommandWrapper { + + private CommandWrapper() { + } + + public static void register(CommandDispatcher dispatcher, org.enginehub.piston.Command command) { + ImmutableList.Builder aliases = ImmutableList.builder(); + aliases.add(command.getName()).addAll(command.getAliases()); + + Command commandRunner = + ctx -> { + WorldEdit.getInstance().getEventBus().post(new com.sk89q.worldedit.event.platform.CommandEvent( + adaptPlayer(ctx.getSource().getPlayer()), + ctx.getInput() + )); + return 0; + }; + + for (String alias : aliases.build()) { + LiteralArgumentBuilder base = literal(alias).executes(commandRunner) + .then(argument("args", StringArgumentType.greedyString()) + .suggests(CommandWrapper::suggest) + .executes(commandRunner)); + if (command.getCondition() != org.enginehub.piston.Command.Condition.TRUE) { + base.requires(requirementsFor(command)); + } + dispatcher.register(base); + } + } + + private static Predicate requirementsFor(org.enginehub.piston.Command mapping) { + return ctx -> { + final Entity entity = ctx.getEntity(); + if (!(entity instanceof ServerPlayerEntity)) { + return true; + } + final Actor actor = FabricAdapter.adaptPlayer(((ServerPlayerEntity) entity)); + InjectedValueStore store = MapBackedValueStore.create(); + store.injectValue(Key.of(Actor.class), context -> Optional.of(actor)); + return mapping.getCondition().satisfied(store); + }; + } + + private static CompletableFuture suggest(CommandContext context, + SuggestionsBuilder builder) throws CommandSyntaxException { + CommandSuggestionEvent event = new CommandSuggestionEvent( + FabricAdapter.adaptPlayer(context.getSource().getPlayer()), + builder.getInput() + ); + WorldEdit.getInstance().getEventBus().post(event); + List suggestions = event.getSuggestions(); + + ImmutableList.Builder result = ImmutableList.builder(); + + for (Substring suggestion : suggestions) { + String suggestionText = suggestion.getSubstring(); + // If at end, we are actually suggesting the next argument + // Ensure there is a space! + if (suggestion.getStart() == suggestion.getEnd() + && suggestion.getEnd() == builder.getInput().length() + && !builder.getInput().endsWith(" ")) { + suggestionText = " " + suggestionText; + } + result.add(new Suggestion( + StringRange.between(suggestion.getStart(), suggestion.getEnd()), + suggestionText + )); + } + + return CompletableFuture.completedFuture( + Suggestions.create(builder.getInput(), result.build()) + ); + } + +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricAdapter.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricAdapter.java new file mode 100644 index 000000000..317274331 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricAdapter.java @@ -0,0 +1,241 @@ +/* + * 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.fabric; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.collect.ImmutableList; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.registry.state.BooleanProperty; +import com.sk89q.worldedit.registry.state.DirectionalProperty; +import com.sk89q.worldedit.registry.state.EnumProperty; +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.World; +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.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.state.StateFactory; +import net.minecraft.state.property.DirectionProperty; +import net.minecraft.util.Identifier; +import net.minecraft.util.StringIdentifiable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.Biome; + +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; + +public final class FabricAdapter { + + private FabricAdapter() { + } + + public static World adapt(net.minecraft.world.World world) { + return new FabricWorld(world); + } + + public static Biome adapt(BiomeType biomeType) { + return Registry.BIOME.get(new Identifier(biomeType.getId())); + } + + public static BiomeType adapt(Biome biome) { + return BiomeTypes.get(Registry.BIOME.getId(biome).toString()); + } + + public static Vector3 adapt(Vec3d vector) { + return Vector3.at(vector.x, vector.y, vector.z); + } + + public static BlockVector3 adapt(BlockPos pos) { + return BlockVector3.at(pos.getX(), pos.getY(), pos.getZ()); + } + + public static Vec3d toVec3(BlockVector3 vector) { + return new Vec3d(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); + } + + public static net.minecraft.util.math.Direction adapt(Direction face) { + switch (face) { + case NORTH: return net.minecraft.util.math.Direction.NORTH; + case SOUTH: return net.minecraft.util.math.Direction.SOUTH; + case WEST: return net.minecraft.util.math.Direction.WEST; + case EAST: return net.minecraft.util.math.Direction.EAST; + case DOWN: return net.minecraft.util.math.Direction.DOWN; + case UP: + default: + return net.minecraft.util.math.Direction.UP; + } + } + + public static Direction adaptEnumFacing(net.minecraft.util.math.Direction face) { + switch (face) { + case NORTH: return Direction.NORTH; + case SOUTH: return Direction.SOUTH; + case WEST: return Direction.WEST; + case EAST: return Direction.EAST; + case DOWN: return Direction.DOWN; + case UP: + default: + return Direction.UP; + } + } + + public static BlockPos toBlockPos(BlockVector3 vector) { + return new BlockPos(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); + } + + public static Property adaptProperty(net.minecraft.state.property.Property property) { + if (property instanceof net.minecraft.state.property.BooleanProperty) { + return new BooleanProperty(property.getName(), ImmutableList.copyOf(((net.minecraft.state.property.BooleanProperty) property).getValues())); + } + if (property instanceof net.minecraft.state.property.IntProperty) { + return new IntegerProperty(property.getName(), ImmutableList.copyOf(((net.minecraft.state.property.IntProperty) property).getValues())); + } + if (property instanceof DirectionProperty) { + return new DirectionalProperty(property.getName(), ((DirectionProperty) property).getValues().stream() + .map(FabricAdapter::adaptEnumFacing) + .collect(Collectors.toList())); + } + if (property instanceof net.minecraft.state.property.EnumProperty) { + // Note: do not make x.asString a method reference. + // It will cause runtime bootstrap exceptions. + return new EnumProperty(property.getName(), ((net.minecraft.state.property.EnumProperty) property).getValues().stream() + .map(x -> x.asString()) + .collect(Collectors.toList())); + } + return new PropertyAdapter<>(property); + } + + public static Map, Object> adaptProperties(BlockType block, Map, Comparable> mcProps) { + Map, Object> props = new TreeMap<>(Comparator.comparing(Property::getName)); + for (Map.Entry, Comparable> prop : mcProps.entrySet()) { + Object value = prop.getValue(); + if (prop.getKey() instanceof DirectionProperty) { + value = adaptEnumFacing((net.minecraft.util.math.Direction) value); + } else if (prop.getKey() instanceof net.minecraft.state.property.EnumProperty) { + value = ((StringIdentifiable) value).asString(); + } + props.put(block.getProperty(prop.getKey().getName()), value); + } + return props; + } + + private static net.minecraft.block.BlockState applyProperties(StateFactory stateContainer, + net.minecraft.block.BlockState newState, Map, Object> states) { + for (Map.Entry, Object> state : states.entrySet()) { + net.minecraft.state.property.Property property = stateContainer.getProperty(state.getKey().getName()); + Comparable value = (Comparable) state.getValue(); + // we may need to adapt this value, depending on the source prop + if (property instanceof DirectionProperty) { + Direction dir = (Direction) value; + value = adapt(dir); + } else if (property instanceof net.minecraft.state.property.EnumProperty) { + String enumName = (String) value; + value = ((net.minecraft.state.property.EnumProperty) property).getValue((String) value).orElseGet(() -> { + throw new IllegalStateException("Enum property " + property.getName() + " does not contain " + enumName); + }); + } + + newState = newState.with(property, value); + } + return newState; + } + + public static net.minecraft.block.BlockState adapt(BlockState blockState) { + Block mcBlock = adapt(blockState.getBlockType()); + net.minecraft.block.BlockState newState = mcBlock.getDefaultState(); + Map, Object> states = blockState.getStates(); + return applyProperties(mcBlock.getStateFactory(), newState, states); + } + + public static BlockState adapt(net.minecraft.block.BlockState blockState) { + BlockType blockType = adapt(blockState.getBlock()); + return blockType.getState(adaptProperties(blockType, blockState.getEntries())); + } + + public static Block adapt(BlockType blockType) { + return Registry.BLOCK.get(new Identifier(blockType.getId())); + } + + public static BlockType adapt(Block block) { + return BlockTypes.get(Registry.BLOCK.getId(block).toString()); + } + + public static Item adapt(ItemType itemType) { + return Registry.ITEM.get(new Identifier(itemType.getId())); + } + + public static ItemType adapt(Item item) { + return ItemTypes.get(Registry.ITEM.getId(item).toString()); + } + + public static ItemStack adapt(BaseItemStack baseItemStack) { + net.minecraft.nbt.CompoundTag fabricCompound = null; + if (baseItemStack.getNbtData() != null) { + fabricCompound = NBTConverter.toNative(baseItemStack.getNbtData()); + } + final ItemStack itemStack = new ItemStack(adapt(baseItemStack.getType()), baseItemStack.getAmount()); + itemStack.setTag(fabricCompound); + return itemStack; + } + + public static BaseItemStack adapt(ItemStack itemStack) { + CompoundTag tag = NBTConverter.fromNative(itemStack.toTag(new net.minecraft.nbt.CompoundTag())); + if (tag.getValue().isEmpty()) { + tag = null; + } else { + final Tag tagTag = tag.getValue().get("tag"); + if (tagTag instanceof CompoundTag) { + tag = ((CompoundTag) tagTag); + } else { + tag = null; + } + } + return new BaseItemStack(adapt(itemStack.getItem()), tag, itemStack.getCount()); + } + + /** + * Get the WorldEdit proxy for the given player. + * + * @param player the player + * @return the WorldEdit player + */ + public static FabricPlayer adaptPlayer(ServerPlayerEntity player) { + checkNotNull(player); + return new FabricPlayer(player); + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBiomeRegistry.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBiomeRegistry.java new file mode 100644 index 000000000..fbf883101 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBiomeRegistry.java @@ -0,0 +1,58 @@ +/* + * 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.fabric; + +import com.sk89q.worldedit.world.biome.BiomeData; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import net.minecraft.world.biome.Biome; + +/** + * Provides access to biome data in Fabric. + */ +class FabricBiomeRegistry implements BiomeRegistry { + + @Override + public BiomeData getData(BiomeType biome) { + return new FabricBiomeData(FabricAdapter.adapt(biome)); + } + + /** + * Cached biome data information. + */ + private static class FabricBiomeData implements BiomeData { + private final Biome biome; + + /** + * Create a new instance. + * + * @param biome the base biome + */ + private FabricBiomeData(Biome biome) { + this.biome = biome; + } + + @Override + public String getName() { + return biome.getTextComponent().getString(); + } + } + +} \ No newline at end of file diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockCategoryRegistry.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockCategoryRegistry.java new file mode 100644 index 000000000..bbf6ffbd3 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockCategoryRegistry.java @@ -0,0 +1,46 @@ +/* + * 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.fabric; + +import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; +import net.minecraft.tag.BlockTags; +import net.minecraft.tag.Tag; +import net.minecraft.util.Identifier; + +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class FabricBlockCategoryRegistry implements BlockCategoryRegistry { + @Override + public Set getCategorisedByName(String category) { + return Optional.ofNullable(BlockTags.getContainer().get(new Identifier(category))) + .map(Tag::values).orElse(Collections.emptySet()) + .stream().map(FabricAdapter::adapt).collect(Collectors.toSet()); + } + + @Override + public Set getAll(Category category) { + return getCategorisedByName(category.getId()); + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockMaterial.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockMaterial.java new file mode 100644 index 000000000..c9fc86e02 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockMaterial.java @@ -0,0 +1,93 @@ +/* + * 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.fabric; + +import com.sk89q.worldedit.world.registry.BlockMaterial; +import com.sk89q.worldedit.world.registry.PassthroughBlockMaterial; +import net.minecraft.block.Material; +import net.minecraft.block.piston.PistonBehavior; + +import javax.annotation.Nullable; + +/** + * Fabric block material that pulls as much info as possible from the Minecraft + * Material, and passes the rest to another implementation, typically the + * bundled block info. + */ +public class FabricBlockMaterial extends PassthroughBlockMaterial { + + private final Material delegate; + + public FabricBlockMaterial(Material delegate, @Nullable BlockMaterial secondary) { + super(secondary); + this.delegate = delegate; + } + + @Override + public boolean isAir() { + return delegate == Material.AIR || super.isAir(); + } + + @Override + public boolean isOpaque() { + return delegate.blocksLight(); + } + + @Override + public boolean isLiquid() { + return delegate.isLiquid(); + } + + @Override + public boolean isSolid() { + return delegate.isSolid(); + } + + @Override + public boolean isFragileWhenPushed() { + return delegate.getPistonBehavior() == PistonBehavior.DESTROY; + } + + @Override + public boolean isUnpushable() { + return delegate.getPistonBehavior() == PistonBehavior.BLOCK; + } + + @Override + public boolean isMovementBlocker() { + return delegate.blocksMovement(); + } + + @Override + public boolean isBurnable() { + return delegate.isBurnable(); + } + + @Override + public boolean isToolRequired() { + return !delegate.canBreakByHand(); + } + + @Override + public boolean isReplacedDuringPlacement() { + return delegate.isReplaceable(); + } + +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockRegistry.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockRegistry.java new file mode 100644 index 000000000..1d219c90c --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockRegistry.java @@ -0,0 +1,80 @@ +/* + * 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.fabric; + +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BlockMaterial; +import com.sk89q.worldedit.world.registry.BundledBlockRegistry; +import net.fabricmc.api.EnvType; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.block.Block; +import net.minecraft.block.Material; + +import javax.annotation.Nullable; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.OptionalInt; +import java.util.TreeMap; + +public class FabricBlockRegistry extends BundledBlockRegistry { + + private Map materialMap = new HashMap<>(); + + @Nullable + @Override + public String getName(BlockType blockType) { + Block block = FabricAdapter.adapt(blockType); + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { + return block.getTextComponent().getFormattedText(); + } else { + return super.getName(blockType); + } + } + + @Override + public BlockMaterial getMaterial(BlockType blockType) { + Block block = FabricAdapter.adapt(blockType); + return materialMap.computeIfAbsent(block.getDefaultState().getMaterial(), + m -> new FabricBlockMaterial(m, super.getMaterial(blockType))); + } + + @Override + public Map> getProperties(BlockType blockType) { + Block block = FabricAdapter.adapt(blockType); + Map> map = new TreeMap<>(); + Collection> propertyKeys = block + .getDefaultState() + .getProperties(); + for (net.minecraft.state.property.Property key : propertyKeys) { + map.put(key.getName(), FabricAdapter.adaptProperty(key)); + } + return map; + } + + @Override + public OptionalInt getInternalBlockStateId(BlockState state) { + net.minecraft.block.BlockState equivalent = FabricAdapter.adapt(state); + return OptionalInt.of(Block.getRawIdFromState(equivalent)); + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricConfiguration.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricConfiguration.java new file mode 100644 index 000000000..ab00d6f89 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricConfiguration.java @@ -0,0 +1,45 @@ +/* + * 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.fabric; + +import com.sk89q.worldedit.util.PropertiesConfiguration; + +import java.io.File; + +public class FabricConfiguration extends PropertiesConfiguration { + + public boolean creativeEnable = false; + public boolean cheatMode = false; + + public FabricConfiguration(FabricWorldEdit mod) { + super(new File(mod.getWorkingDir(), "worldedit.properties")); + } + + @Override + protected void loadExtra() { + creativeEnable = getBool("use-in-creative", false); + cheatMode = getBool("cheat-mode", false); + } + + @Override + public File getWorkingDirectory() { + return FabricWorldEdit.inst.getWorkingDir(); + } +} \ No newline at end of file diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricDataFixer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricDataFixer.java new file mode 100644 index 000000000..c04e06840 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricDataFixer.java @@ -0,0 +1,2728 @@ +/* + * 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.fabric; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.datafixers.DSL.TypeReference; +import com.mojang.datafixers.DataFixer; +import com.mojang.datafixers.DataFixerBuilder; +import com.mojang.datafixers.Dynamic; +import com.mojang.datafixers.schemas.Schema; +import com.sk89q.jnbt.CompoundTag; +import net.minecraft.datafixers.NbtOps; +import net.minecraft.datafixers.Schemas; +import net.minecraft.datafixers.TypeReferences; +import net.minecraft.nbt.FloatTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.util.DyeColor; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; +import net.minecraft.util.math.Direction; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Executor; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; + +/** + * Handles converting all Pre 1.13.2 data using the Legacy DataFix System (ported to 1.13.2) + * + * We register a DFU Fixer per Legacy Data Version and apply the fixes using legacy strategy + * which is safer, faster and cleaner code. + * + * The pre DFU code did not fail when the Source version was unknown. + * + * This class also provides util methods for converting compounds to wrap the update call to + * receive the source version in the compound + * + */ +@SuppressWarnings("UnnecessarilyQualifiedStaticUsage") +class FabricDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.world.DataFixer { + + @SuppressWarnings("unchecked") + @Override + public T fixUp(FixType type, T original, int srcVer) { + if (type == FixTypes.CHUNK) { + return (T) fixChunk((CompoundTag) original, srcVer); + } else if (type == FixTypes.BLOCK_ENTITY) { + return (T) fixBlockEntity((CompoundTag) original, srcVer); + } else if (type == FixTypes.ENTITY) { + return (T) fixEntity((CompoundTag) original, srcVer); + } else if (type == FixTypes.BLOCK_STATE) { + return (T) fixBlockState((String) original, srcVer); + } else if (type == FixTypes.ITEM_TYPE) { + return (T) fixItemType((String) original, srcVer); + } else if (type == FixTypes.BIOME) { + return (T) fixBiome((String) original, srcVer); + } + return original; + } + + private CompoundTag fixChunk(CompoundTag originalChunk, int srcVer) { + net.minecraft.nbt.CompoundTag tag = NBTConverter.toNative(originalChunk); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.CHUNK, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private CompoundTag fixBlockEntity(CompoundTag origTileEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = NBTConverter.toNative(origTileEnt); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.BLOCK_ENTITY, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private CompoundTag fixEntity(CompoundTag origEnt, int srcVer) { + net.minecraft.nbt.CompoundTag tag = NBTConverter.toNative(origEnt); + net.minecraft.nbt.CompoundTag fixed = convert(LegacyType.ENTITY, tag, srcVer); + return NBTConverter.fromNative(fixed); + } + + private String fixBlockState(String blockState, int srcVer) { + net.minecraft.nbt.CompoundTag stateNBT = stateToNBT(blockState); + Dynamic dynamic = new Dynamic<>(OPS_NBT, stateNBT); + net.minecraft.nbt.CompoundTag fixed = (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(TypeReferences.BLOCK_STATE, dynamic, srcVer, DATA_VERSION).getValue(); + return nbtToState(fixed); + } + + private String nbtToState(net.minecraft.nbt.CompoundTag tagCompound) { + StringBuilder sb = new StringBuilder(); + sb.append(tagCompound.getString("Name")); + if (tagCompound.containsKey("Properties", 10)) { + sb.append('['); + net.minecraft.nbt.CompoundTag props = tagCompound.getCompound("Properties"); + sb.append(props.getKeys().stream().map(k -> k + "=" + props.getString(k).replace("\"", "")).collect(Collectors.joining(","))); + sb.append(']'); + } + return sb.toString(); + } + + private static net.minecraft.nbt.CompoundTag stateToNBT(String blockState) { + int propIdx = blockState.indexOf('['); + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + if (propIdx < 0) { + tag.putString("Name", blockState); + } else { + tag.putString("Name", blockState.substring(0, propIdx)); + net.minecraft.nbt.CompoundTag propTag = new net.minecraft.nbt.CompoundTag(); + String props = blockState.substring(propIdx + 1, blockState.length() - 1); + String[] propArr = props.split(","); + for (String pair : propArr) { + final String[] split = pair.split("="); + propTag.putString(split[0], split[1]); + } + tag.put("Properties", propTag); + } + return tag; + } + + private String fixBiome(String key, int srcVer) { + return fixName(key, srcVer, TypeReferences.BIOME); + } + + private String fixItemType(String key, int srcVer) { + return fixName(key, srcVer, TypeReferences.ITEM_NAME); + } + + private static String fixName(String key, int srcVer, TypeReference type) { + return INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, new StringTag(key)), srcVer, DATA_VERSION) + .asString().orElse(key); + } + + private static final NbtOps OPS_NBT = NbtOps.INSTANCE; + private static final int LEGACY_VERSION = 1343; + private static int DATA_VERSION; + private static FabricDataFixer INSTANCE; + + private final Map> converters = new EnumMap<>(LegacyType.class); + private final Map> inspectors = new EnumMap<>(LegacyType.class); + + // Set on build + private DataFixer fixer; + private static final Map DFU_TO_LEGACY = new HashMap<>(); + + public enum LegacyType { + LEVEL(TypeReferences.LEVEL), + PLAYER(TypeReferences.PLAYER), + CHUNK(TypeReferences.CHUNK), + BLOCK_ENTITY(TypeReferences.BLOCK_ENTITY), + ENTITY(TypeReferences.ENTITY), + ITEM_INSTANCE(TypeReferences.ITEM_STACK), + OPTIONS(TypeReferences.OPTIONS), + STRUCTURE(TypeReferences.STRUCTURE); + + private final TypeReference type; + + LegacyType(TypeReference type) { + this.type = type; + DFU_TO_LEGACY.put(type.typeName(), this); + } + + public TypeReference getDFUType() { + return type; + } + } + + FabricDataFixer(int dataVersion) { + super(dataVersion); + DATA_VERSION = dataVersion; + INSTANCE = this; + registerConverters(); + registerInspectors(); + this.fixer = new WrappedDataFixer(Schemas.getFixer()); + } + + @Override + public DataFixer build(final Executor executor) { + return fixer; + } + + private class WrappedDataFixer implements DataFixer { + private final DataFixer realFixer; + + WrappedDataFixer(DataFixer realFixer) { + this.realFixer = realFixer; + } + + @Override + public Dynamic update(TypeReference type, Dynamic dynamic, int sourceVer, int targetVer) { + LegacyType legacyType = DFU_TO_LEGACY.get(type.typeName()); + if (sourceVer < LEGACY_VERSION && legacyType != null) { + net.minecraft.nbt.CompoundTag cmp = (net.minecraft.nbt.CompoundTag) dynamic.getValue(); + int desiredVersion = Math.min(targetVer, LEGACY_VERSION); + + cmp = convert(legacyType, cmp, sourceVer, desiredVersion); + sourceVer = desiredVersion; + dynamic = new Dynamic(OPS_NBT, cmp); + } + return realFixer.update(type, dynamic, sourceVer, targetVer); + } + + private net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int desiredVersion) { + List converters = FabricDataFixer.this.converters.get(type); + if (converters != null && !converters.isEmpty()) { + for (DataConverter converter : converters) { + int dataVersion = converter.getDataVersion(); + if (dataVersion > sourceVer && dataVersion <= desiredVersion) { + cmp = converter.convert(cmp); + } + } + } + + List inspectors = FabricDataFixer.this.inspectors.get(type); + if (inspectors != null && !inspectors.isEmpty()) { + for (DataInspector inspector : inspectors) { + cmp = inspector.inspect(cmp, sourceVer, desiredVersion); + } + } + + return cmp; + } + + @Override + public Schema getSchema(int i) { + return realFixer.getSchema(i); + } + } + + public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp) { + return convert(type.getDFUType(), cmp); + } + + public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer) { + return convert(type.getDFUType(), cmp, sourceVer); + } + + public static net.minecraft.nbt.CompoundTag convert(LegacyType type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + return convert(type.getDFUType(), cmp, sourceVer, targetVer); + } + + public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp) { + int i = cmp.containsKey("DataVersion", 99) ? cmp.getInt("DataVersion") : -1; + return convert(type, cmp, i); + } + + public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp, int sourceVer) { + return convert(type, cmp, sourceVer, DATA_VERSION); + } + + public static net.minecraft.nbt.CompoundTag convert(TypeReference type, net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (sourceVer >= targetVer) { + return cmp; + } + return (net.minecraft.nbt.CompoundTag) INSTANCE.fixer.update(type, new Dynamic<>(OPS_NBT, cmp), sourceVer, targetVer).getValue(); + } + + + public interface DataInspector { + net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer); + } + + public interface DataConverter { + + int getDataVersion(); + + net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp); + } + + + private void registerInspector(LegacyType type, DataInspector inspector) { + this.inspectors.computeIfAbsent(type, k -> new ArrayList<>()).add(inspector); + } + + private void registerConverter(LegacyType type, DataConverter converter) { + int version = converter.getDataVersion(); + + List list = this.converters.computeIfAbsent(type, k -> new ArrayList<>()); + if (!list.isEmpty() && list.get(list.size() - 1).getDataVersion() > version) { + for (int j = 0; j < list.size(); ++j) { + if (list.get(j).getDataVersion() > version) { + list.add(j, converter); + break; + } + } + } else { + list.add(converter); + } + } + + private void registerInspectors() { + registerEntityItemList("EntityHorseDonkey", "SaddleItem", "Items"); + registerEntityItemList("EntityHorseMule", "Items"); + registerEntityItemList("EntityMinecartChest", "Items"); + registerEntityItemList("EntityMinecartHopper", "Items"); + registerEntityItemList("EntityVillager", "Inventory"); + registerEntityItemListEquipment("EntityArmorStand"); + registerEntityItemListEquipment("EntityBat"); + registerEntityItemListEquipment("EntityBlaze"); + registerEntityItemListEquipment("EntityCaveSpider"); + registerEntityItemListEquipment("EntityChicken"); + registerEntityItemListEquipment("EntityCow"); + registerEntityItemListEquipment("EntityCreeper"); + registerEntityItemListEquipment("EntityEnderDragon"); + registerEntityItemListEquipment("EntityEnderman"); + registerEntityItemListEquipment("EntityEndermite"); + registerEntityItemListEquipment("EntityEvoker"); + registerEntityItemListEquipment("EntityGhast"); + registerEntityItemListEquipment("EntityGiantZombie"); + registerEntityItemListEquipment("EntityGuardian"); + registerEntityItemListEquipment("EntityGuardianElder"); + registerEntityItemListEquipment("EntityHorse"); + registerEntityItemListEquipment("EntityHorseDonkey"); + registerEntityItemListEquipment("EntityHorseMule"); + registerEntityItemListEquipment("EntityHorseSkeleton"); + registerEntityItemListEquipment("EntityHorseZombie"); + registerEntityItemListEquipment("EntityIronGolem"); + registerEntityItemListEquipment("EntityMagmaCube"); + registerEntityItemListEquipment("EntityMushroomCow"); + registerEntityItemListEquipment("EntityOcelot"); + registerEntityItemListEquipment("EntityPig"); + registerEntityItemListEquipment("EntityPigZombie"); + registerEntityItemListEquipment("EntityRabbit"); + registerEntityItemListEquipment("EntitySheep"); + registerEntityItemListEquipment("EntityShulker"); + registerEntityItemListEquipment("EntitySilverfish"); + registerEntityItemListEquipment("EntitySkeleton"); + registerEntityItemListEquipment("EntitySkeletonStray"); + registerEntityItemListEquipment("EntitySkeletonWither"); + registerEntityItemListEquipment("EntitySlime"); + registerEntityItemListEquipment("EntitySnowman"); + registerEntityItemListEquipment("EntitySpider"); + registerEntityItemListEquipment("EntitySquid"); + registerEntityItemListEquipment("EntityVex"); + registerEntityItemListEquipment("EntityVillager"); + registerEntityItemListEquipment("EntityVindicator"); + registerEntityItemListEquipment("EntityWitch"); + registerEntityItemListEquipment("EntityWither"); + registerEntityItemListEquipment("EntityWolf"); + registerEntityItemListEquipment("EntityZombie"); + registerEntityItemListEquipment("EntityZombieHusk"); + registerEntityItemListEquipment("EntityZombieVillager"); + registerEntityItemSingle("EntityFireworks", "FireworksItem"); + registerEntityItemSingle("EntityHorse", "ArmorItem"); + registerEntityItemSingle("EntityHorse", "SaddleItem"); + registerEntityItemSingle("EntityHorseMule", "SaddleItem"); + registerEntityItemSingle("EntityHorseSkeleton", "SaddleItem"); + registerEntityItemSingle("EntityHorseZombie", "SaddleItem"); + registerEntityItemSingle("EntityItem", "Item"); + registerEntityItemSingle("EntityItemFrame", "Item"); + registerEntityItemSingle("EntityPotion", "Potion"); + + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItem("TileEntityRecordPlayer", "RecordItem")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityBrewingStand", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityChest", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityDispenser", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityDropper", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityFurnace", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityHopper", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorItemList("TileEntityShulkerBox", "Items")); + registerInspector(LegacyType.BLOCK_ENTITY, new DataInspectorMobSpawnerMobs()); + registerInspector(LegacyType.CHUNK, new DataInspectorChunks()); + registerInspector(LegacyType.ENTITY, new DataInspectorCommandBlock()); + registerInspector(LegacyType.ENTITY, new DataInspectorEntityPassengers()); + registerInspector(LegacyType.ENTITY, new DataInspectorMobSpawnerMinecart()); + registerInspector(LegacyType.ENTITY, new DataInspectorVillagers()); + registerInspector(LegacyType.ITEM_INSTANCE, new DataInspectorBlockEntity()); + registerInspector(LegacyType.ITEM_INSTANCE, new DataInspectorEntity()); + registerInspector(LegacyType.LEVEL, new DataInspectorLevelPlayer()); + registerInspector(LegacyType.PLAYER, new DataInspectorPlayer()); + registerInspector(LegacyType.PLAYER, new DataInspectorPlayerVehicle()); + registerInspector(LegacyType.STRUCTURE, new DataInspectorStructure()); + } + + private void registerConverters() { + registerConverter(LegacyType.ENTITY, new DataConverterEquipment()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterSignText()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterMaterialId()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterPotionId()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterSpawnEgg()); + registerConverter(LegacyType.ENTITY, new DataConverterMinecart()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterMobSpawner()); + registerConverter(LegacyType.ENTITY, new DataConverterUUID()); + registerConverter(LegacyType.ENTITY, new DataConverterHealth()); + registerConverter(LegacyType.ENTITY, new DataConverterSaddle()); + registerConverter(LegacyType.ENTITY, new DataConverterHanging()); + registerConverter(LegacyType.ENTITY, new DataConverterDropChances()); + registerConverter(LegacyType.ENTITY, new DataConverterRiding()); + registerConverter(LegacyType.ENTITY, new DataConverterArmorStand()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBook()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterCookedFish()); + registerConverter(LegacyType.ENTITY, new DataConverterZombie()); + registerConverter(LegacyType.OPTIONS, new DataConverterVBO()); + registerConverter(LegacyType.ENTITY, new DataConverterGuardian()); + registerConverter(LegacyType.ENTITY, new DataConverterSkeleton()); + registerConverter(LegacyType.ENTITY, new DataConverterZombieType()); + registerConverter(LegacyType.ENTITY, new DataConverterHorse()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterTileEntity()); + registerConverter(LegacyType.ENTITY, new DataConverterEntity()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBanner()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterPotionWater()); + registerConverter(LegacyType.ENTITY, new DataConverterShulker()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterShulkerBoxItem()); + registerConverter(LegacyType.BLOCK_ENTITY, new DataConverterShulkerBoxBlock()); + registerConverter(LegacyType.OPTIONS, new DataConverterLang()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterTotem()); + registerConverter(LegacyType.CHUNK, new DataConverterBedBlock()); + registerConverter(LegacyType.ITEM_INSTANCE, new DataConverterBedItem()); + } + + private void registerEntityItemList(String type, String... keys) { + registerInspector(LegacyType.ENTITY, new DataInspectorItemList(type, keys)); + } + + private void registerEntityItemSingle(String type, String key) { + registerInspector(LegacyType.ENTITY, new DataInspectorItem(type, key)); + } + + private void registerEntityItemListEquipment(String type) { + registerEntityItemList(type, "ArmorItems", "HandItems"); + } + private static final Map OLD_ID_TO_KEY_MAP = new HashMap<>(); + + static { + final Map map = OLD_ID_TO_KEY_MAP; + map.put("EntityItem", new Identifier("item")); + map.put("EntityExperienceOrb", new Identifier("xp_orb")); + map.put("EntityAreaEffectCloud", new Identifier("area_effect_cloud")); + map.put("EntityGuardianElder", new Identifier("elder_guardian")); + map.put("EntitySkeletonWither", new Identifier("wither_skeleton")); + map.put("EntitySkeletonStray", new Identifier("stray")); + map.put("EntityEgg", new Identifier("egg")); + map.put("EntityLeash", new Identifier("leash_knot")); + map.put("EntityPainting", new Identifier("painting")); + map.put("EntityTippedArrow", new Identifier("arrow")); + map.put("EntitySnowball", new Identifier("snowball")); + map.put("EntityLargeFireball", new Identifier("fireball")); + map.put("EntitySmallFireball", new Identifier("small_fireball")); + map.put("EntityEnderPearl", new Identifier("ender_pearl")); + map.put("EntityEnderSignal", new Identifier("eye_of_ender_signal")); + map.put("EntityPotion", new Identifier("potion")); + map.put("EntityThrownExpBottle", new Identifier("xp_bottle")); + map.put("EntityItemFrame", new Identifier("item_frame")); + map.put("EntityWitherSkull", new Identifier("wither_skull")); + map.put("EntityTNTPrimed", new Identifier("tnt")); + map.put("EntityFallingBlock", new Identifier("falling_block")); + map.put("EntityFireworks", new Identifier("fireworks_rocket")); + map.put("EntityZombieHusk", new Identifier("husk")); + map.put("EntitySpectralArrow", new Identifier("spectral_arrow")); + map.put("EntityShulkerBullet", new Identifier("shulker_bullet")); + map.put("EntityDragonFireball", new Identifier("dragon_fireball")); + map.put("EntityZombieVillager", new Identifier("zombie_villager")); + map.put("EntityHorseSkeleton", new Identifier("skeleton_horse")); + map.put("EntityHorseZombie", new Identifier("zombie_horse")); + map.put("EntityArmorStand", new Identifier("armor_stand")); + map.put("EntityHorseDonkey", new Identifier("donkey")); + map.put("EntityHorseMule", new Identifier("mule")); + map.put("EntityEvokerFangs", new Identifier("evocation_fangs")); + map.put("EntityEvoker", new Identifier("evocation_illager")); + map.put("EntityVex", new Identifier("vex")); + map.put("EntityVindicator", new Identifier("vindication_illager")); + map.put("EntityIllagerIllusioner", new Identifier("illusion_illager")); + map.put("EntityMinecartCommandBlock", new Identifier("commandblock_minecart")); + map.put("EntityBoat", new Identifier("boat")); + map.put("EntityMinecartRideable", new Identifier("minecart")); + map.put("EntityMinecartChest", new Identifier("chest_minecart")); + map.put("EntityMinecartFurnace", new Identifier("furnace_minecart")); + map.put("EntityMinecartTNT", new Identifier("tnt_minecart")); + map.put("EntityMinecartHopper", new Identifier("hopper_minecart")); + map.put("EntityMinecartMobSpawner", new Identifier("spawner_minecart")); + map.put("EntityCreeper", new Identifier("creeper")); + map.put("EntitySkeleton", new Identifier("skeleton")); + map.put("EntitySpider", new Identifier("spider")); + map.put("EntityGiantZombie", new Identifier("giant")); + map.put("EntityZombie", new Identifier("zombie")); + map.put("EntitySlime", new Identifier("slime")); + map.put("EntityGhast", new Identifier("ghast")); + map.put("EntityPigZombie", new Identifier("zombie_pigman")); + map.put("EntityEnderman", new Identifier("enderman")); + map.put("EntityCaveSpider", new Identifier("cave_spider")); + map.put("EntitySilverfish", new Identifier("silverfish")); + map.put("EntityBlaze", new Identifier("blaze")); + map.put("EntityMagmaCube", new Identifier("magma_cube")); + map.put("EntityEnderDragon", new Identifier("ender_dragon")); + map.put("EntityWither", new Identifier("wither")); + map.put("EntityBat", new Identifier("bat")); + map.put("EntityWitch", new Identifier("witch")); + map.put("EntityEndermite", new Identifier("endermite")); + map.put("EntityGuardian", new Identifier("guardian")); + map.put("EntityShulker", new Identifier("shulker")); + map.put("EntityPig", new Identifier("pig")); + map.put("EntitySheep", new Identifier("sheep")); + map.put("EntityCow", new Identifier("cow")); + map.put("EntityChicken", new Identifier("chicken")); + map.put("EntitySquid", new Identifier("squid")); + map.put("EntityWolf", new Identifier("wolf")); + map.put("EntityMushroomCow", new Identifier("mooshroom")); + map.put("EntitySnowman", new Identifier("snowman")); + map.put("EntityOcelot", new Identifier("ocelot")); + map.put("EntityIronGolem", new Identifier("villager_golem")); + map.put("EntityHorse", new Identifier("horse")); + map.put("EntityRabbit", new Identifier("rabbit")); + map.put("EntityPolarBear", new Identifier("polar_bear")); + map.put("EntityLlama", new Identifier("llama")); + map.put("EntityLlamaSpit", new Identifier("llama_spit")); + map.put("EntityParrot", new Identifier("parrot")); + map.put("EntityVillager", new Identifier("villager")); + map.put("EntityEnderCrystal", new Identifier("ender_crystal")); + map.put("TileEntityFurnace", new Identifier("furnace")); + map.put("TileEntityChest", new Identifier("chest")); + map.put("TileEntityEnderChest", new Identifier("ender_chest")); + map.put("TileEntityRecordPlayer", new Identifier("jukebox")); + map.put("TileEntityDispenser", new Identifier("dispenser")); + map.put("TileEntityDropper", new Identifier("dropper")); + map.put("TileEntitySign", new Identifier("sign")); + map.put("TileEntityMobSpawner", new Identifier("mob_spawner")); + map.put("TileEntityNote", new Identifier("noteblock")); + map.put("TileEntityPiston", new Identifier("piston")); + map.put("TileEntityBrewingStand", new Identifier("brewing_stand")); + map.put("TileEntityEnchantTable", new Identifier("enchanting_table")); + map.put("TileEntityEnderPortal", new Identifier("end_portal")); + map.put("TileEntityBeacon", new Identifier("beacon")); + map.put("TileEntitySkull", new Identifier("skull")); + map.put("TileEntityLightDetector", new Identifier("daylight_detector")); + map.put("TileEntityHopper", new Identifier("hopper")); + map.put("TileEntityComparator", new Identifier("comparator")); + map.put("TileEntityFlowerPot", new Identifier("flower_pot")); + map.put("TileEntityBanner", new Identifier("banner")); + map.put("TileEntityStructure", new Identifier("structure_block")); + map.put("TileEntityEndGateway", new Identifier("end_gateway")); + map.put("TileEntityCommand", new Identifier("command_block")); + map.put("TileEntityShulkerBox", new Identifier("shulker_box")); + map.put("TileEntityBed", new Identifier("bed")); + } + + private static Identifier getKey(String type) { + final Identifier key = OLD_ID_TO_KEY_MAP.get(type); + if (key == null) { + throw new IllegalArgumentException("Unknown mapping for " + type); + } + return key; + } + + private static void convertCompound(LegacyType type, net.minecraft.nbt.CompoundTag cmp, String key, int sourceVer, int targetVer) { + cmp.put(key, convert(type, cmp.getCompound(key), sourceVer, targetVer)); + } + + private static void convertItem(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.containsKey(key, 10)) { + convertCompound(LegacyType.ITEM_INSTANCE, nbttagcompound, key, sourceVer, targetVer); + } + } + + private static void convertItems(net.minecraft.nbt.CompoundTag nbttagcompound, String key, int sourceVer, int targetVer) { + if (nbttagcompound.containsKey(key, 9)) { + ListTag nbttaglist = nbttagcompound.getList(key, 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.add(j, convert(LegacyType.ITEM_INSTANCE, nbttaglist.getCompoundTag(j), sourceVer, targetVer)); + } + } + + } + + private static class DataConverterEquipment implements DataConverter { + + DataConverterEquipment() {} + + @Override + public int getDataVersion() { + return 100; + } + + @Override + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + ListTag nbttaglist = cmp.getList("Equipment", 10); + ListTag nbttaglist1; + + if (!nbttaglist.isEmpty() && !cmp.containsKey("HandItems", 10)) { + nbttaglist1 = new ListTag(); + nbttaglist1.add(nbttaglist.get(0)); + nbttaglist1.add(new net.minecraft.nbt.CompoundTag()); + cmp.put("HandItems", nbttaglist1); + } + + if (nbttaglist.size() > 1 && !cmp.containsKey("ArmorItem", 10)) { + nbttaglist1 = new ListTag(); + nbttaglist1.add(nbttaglist.get(1)); + nbttaglist1.add(nbttaglist.get(2)); + nbttaglist1.add(nbttaglist.get(3)); + nbttaglist1.add(nbttaglist.get(4)); + cmp.put("ArmorItems", nbttaglist1); + } + + cmp.remove("Equipment"); + if (cmp.containsKey("DropChances", 9)) { + nbttaglist1 = cmp.getList("DropChances", 5); + ListTag nbttaglist2; + + if (!cmp.containsKey("HandDropChances", 10)) { + nbttaglist2 = new ListTag(); + nbttaglist2.add(new FloatTag(nbttaglist1.getFloat(0))); + nbttaglist2.add(new FloatTag(0.0F)); + cmp.put("HandDropChances", nbttaglist2); + } + + if (!cmp.containsKey("ArmorDropChances", 10)) { + nbttaglist2 = new ListTag(); + nbttaglist2.add(new FloatTag(nbttaglist1.getFloat(1))); + nbttaglist2.add(new FloatTag(nbttaglist1.getFloat(2))); + nbttaglist2.add(new FloatTag(nbttaglist1.getFloat(3))); + nbttaglist2.add(new FloatTag(nbttaglist1.getFloat(4))); + cmp.put("ArmorDropChances", nbttaglist2); + } + + cmp.remove("DropChances"); + } + + return cmp; + } + } + + private static class DataInspectorBlockEntity implements DataInspector { + + private static final Map b = Maps.newHashMap(); + private static final Map c = Maps.newHashMap(); + + DataInspectorBlockEntity() {} + + @Nullable + private static String convertEntityId(int i, String s) { + String key = new Identifier(s).toString(); + if (i < 515 && DataInspectorBlockEntity.b.containsKey(key)) { + return DataInspectorBlockEntity.b.get(key); + } else { + return DataInspectorBlockEntity.c.get(key); + } + } + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (!cmp.containsKey("tag", 10)) { + return cmp; + } else { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.containsKey("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + String s = cmp.getString("id"); + String s1 = convertEntityId(sourceVer, s); + boolean flag; + + if (s1 == null) { + // CraftBukkit - Remove unnecessary warning (occurs when deserializing a Shulker Box item) + // DataInspectorBlockEntity.a.warn("Unable to resolve BlockEntity for ItemInstance: {}", s); + flag = false; + } else { + flag = !nbttagcompound2.containsKey("id"); + nbttagcompound2.putString("id", s1); + } + + convert(LegacyType.BLOCK_ENTITY, nbttagcompound2, sourceVer, targetVer); + if (flag) { + nbttagcompound2.remove("id"); + } + } + + return cmp; + } + } + + static { + Map map = DataInspectorBlockEntity.b; + + map.put("minecraft:furnace", "Furnace"); + map.put("minecraft:lit_furnace", "Furnace"); + map.put("minecraft:chest", "Chest"); + map.put("minecraft:trapped_chest", "Chest"); + map.put("minecraft:ender_chest", "EnderChest"); + map.put("minecraft:jukebox", "RecordPlayer"); + map.put("minecraft:dispenser", "Trap"); + map.put("minecraft:dropper", "Dropper"); + map.put("minecraft:sign", "Sign"); + map.put("minecraft:mob_spawner", "MobSpawner"); + map.put("minecraft:noteblock", "Music"); + map.put("minecraft:brewing_stand", "Cauldron"); + map.put("minecraft:enhanting_table", "EnchantTable"); + map.put("minecraft:command_block", "CommandBlock"); + map.put("minecraft:beacon", "Beacon"); + map.put("minecraft:skull", "Skull"); + map.put("minecraft:daylight_detector", "DLDetector"); + map.put("minecraft:hopper", "Hopper"); + map.put("minecraft:banner", "Banner"); + map.put("minecraft:flower_pot", "FlowerPot"); + map.put("minecraft:repeating_command_block", "CommandBlock"); + map.put("minecraft:chain_command_block", "CommandBlock"); + map.put("minecraft:standing_sign", "Sign"); + map.put("minecraft:wall_sign", "Sign"); + map.put("minecraft:piston_head", "Piston"); + map.put("minecraft:daylight_detector_inverted", "DLDetector"); + map.put("minecraft:unpowered_comparator", "Comparator"); + map.put("minecraft:powered_comparator", "Comparator"); + map.put("minecraft:wall_banner", "Banner"); + map.put("minecraft:standing_banner", "Banner"); + map.put("minecraft:structure_block", "Structure"); + map.put("minecraft:end_portal", "Airportal"); + map.put("minecraft:end_gateway", "EndGateway"); + map.put("minecraft:shield", "Shield"); + map = DataInspectorBlockEntity.c; + map.put("minecraft:furnace", "minecraft:furnace"); + map.put("minecraft:lit_furnace", "minecraft:furnace"); + map.put("minecraft:chest", "minecraft:chest"); + map.put("minecraft:trapped_chest", "minecraft:chest"); + map.put("minecraft:ender_chest", "minecraft:enderchest"); + map.put("minecraft:jukebox", "minecraft:jukebox"); + map.put("minecraft:dispenser", "minecraft:dispenser"); + map.put("minecraft:dropper", "minecraft:dropper"); + map.put("minecraft:sign", "minecraft:sign"); + map.put("minecraft:mob_spawner", "minecraft:mob_spawner"); + map.put("minecraft:noteblock", "minecraft:noteblock"); + map.put("minecraft:brewing_stand", "minecraft:brewing_stand"); + map.put("minecraft:enhanting_table", "minecraft:enchanting_table"); + map.put("minecraft:command_block", "minecraft:command_block"); + map.put("minecraft:beacon", "minecraft:beacon"); + map.put("minecraft:skull", "minecraft:skull"); + map.put("minecraft:daylight_detector", "minecraft:daylight_detector"); + map.put("minecraft:hopper", "minecraft:hopper"); + map.put("minecraft:banner", "minecraft:banner"); + map.put("minecraft:flower_pot", "minecraft:flower_pot"); + map.put("minecraft:repeating_command_block", "minecraft:command_block"); + map.put("minecraft:chain_command_block", "minecraft:command_block"); + map.put("minecraft:shulker_box", "minecraft:shulker_box"); + map.put("minecraft:white_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:orange_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:magenta_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:light_blue_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:yellow_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:lime_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:pink_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:gray_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:silver_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:cyan_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:purple_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:blue_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:brown_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:green_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:red_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:black_shulker_box", "minecraft:shulker_box"); + map.put("minecraft:bed", "minecraft:bed"); + map.put("minecraft:standing_sign", "minecraft:sign"); + map.put("minecraft:wall_sign", "minecraft:sign"); + map.put("minecraft:piston_head", "minecraft:piston"); + map.put("minecraft:daylight_detector_inverted", "minecraft:daylight_detector"); + map.put("minecraft:unpowered_comparator", "minecraft:comparator"); + map.put("minecraft:powered_comparator", "minecraft:comparator"); + map.put("minecraft:wall_banner", "minecraft:banner"); + map.put("minecraft:standing_banner", "minecraft:banner"); + map.put("minecraft:structure_block", "minecraft:structure_block"); + map.put("minecraft:end_portal", "minecraft:end_portal"); + map.put("minecraft:end_gateway", "minecraft:end_gateway"); + map.put("minecraft:shield", "minecraft:shield"); + } + } + + private static class DataInspectorEntity implements DataInspector { + + private static final Logger a = LogManager.getLogger(FabricDataFixer.class); + + DataInspectorEntity() {} + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.containsKey("EntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + String s = cmp.getString("id"); + String s1; + + if ("minecraft:armor_stand".equals(s)) { + s1 = sourceVer < 515 ? "ArmorStand" : "minecraft:armor_stand"; + } else { + if (!"minecraft:spawn_egg".equals(s)) { + return cmp; + } + + s1 = nbttagcompound2.getString("id"); + } + + boolean flag; + + if (s1 == null) { + DataInspectorEntity.a.warn("Unable to resolve Entity for ItemInstance: {}", s); + flag = false; + } else { + flag = !nbttagcompound2.containsKey("id", 8); + nbttagcompound2.putString("id", s1); + } + + convert(LegacyType.ENTITY, nbttagcompound2, sourceVer, targetVer); + if (flag) { + nbttagcompound2.remove("id"); + } + } + + return cmp; + } + } + + + private abstract static class DataInspectorTagged implements DataInspector { + + private final Identifier key; + + DataInspectorTagged(String type) { + this.key = getKey(type); + } + + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (this.key.equals(new Identifier(cmp.getString("id")))) { + cmp = this.inspectChecked(cmp, sourceVer, targetVer); + } + + return cmp; + } + + abstract net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer); + } + + private static class DataInspectorItemList extends DataInspectorTagged { + + private final String[] keys; + + DataInspectorItemList(String oclass, String... astring) { + super(oclass); + this.keys = astring; + } + + net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer) { + for (String s : this.keys) { + FabricDataFixer.convertItems(nbttagcompound, s, sourceVer, targetVer); + } + + return nbttagcompound; + } + } + private static class DataInspectorItem extends DataInspectorTagged { + + private final String[] keys; + + DataInspectorItem(String oclass, String... astring) { + super(oclass); + this.keys = astring; + } + + net.minecraft.nbt.CompoundTag inspectChecked(net.minecraft.nbt.CompoundTag nbttagcompound, int sourceVer, int targetVer) { + for (String key : this.keys) { + FabricDataFixer.convertItem(nbttagcompound, key, sourceVer, targetVer); + } + + return nbttagcompound; + } + } + + private static class DataConverterMaterialId implements DataConverter { + + private static final String[] materials = new String[2268]; + + DataConverterMaterialId() {} + + public int getDataVersion() { + return 102; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.containsKey("id", 99)) { + short short0 = cmp.getShort("id"); + + if (short0 > 0 && short0 < materials.length && materials[short0] != null) { + cmp.putString("id", materials[short0]); + } + } + + return cmp; + } + + static { + materials[1] = "minecraft:stone"; + materials[2] = "minecraft:grass"; + materials[3] = "minecraft:dirt"; + materials[4] = "minecraft:cobblestone"; + materials[5] = "minecraft:planks"; + materials[6] = "minecraft:sapling"; + materials[7] = "minecraft:bedrock"; + materials[8] = "minecraft:flowing_water"; + materials[9] = "minecraft:water"; + materials[10] = "minecraft:flowing_lava"; + materials[11] = "minecraft:lava"; + materials[12] = "minecraft:sand"; + materials[13] = "minecraft:gravel"; + materials[14] = "minecraft:gold_ore"; + materials[15] = "minecraft:iron_ore"; + materials[16] = "minecraft:coal_ore"; + materials[17] = "minecraft:log"; + materials[18] = "minecraft:leaves"; + materials[19] = "minecraft:sponge"; + materials[20] = "minecraft:glass"; + materials[21] = "minecraft:lapis_ore"; + materials[22] = "minecraft:lapis_block"; + materials[23] = "minecraft:dispenser"; + materials[24] = "minecraft:sandstone"; + materials[25] = "minecraft:noteblock"; + materials[27] = "minecraft:golden_rail"; + materials[28] = "minecraft:detector_rail"; + materials[29] = "minecraft:sticky_piston"; + materials[30] = "minecraft:web"; + materials[31] = "minecraft:tallgrass"; + materials[32] = "minecraft:deadbush"; + materials[33] = "minecraft:piston"; + materials[35] = "minecraft:wool"; + materials[37] = "minecraft:yellow_flower"; + materials[38] = "minecraft:red_flower"; + materials[39] = "minecraft:brown_mushroom"; + materials[40] = "minecraft:red_mushroom"; + materials[41] = "minecraft:gold_block"; + materials[42] = "minecraft:iron_block"; + materials[43] = "minecraft:double_stone_slab"; + materials[44] = "minecraft:stone_slab"; + materials[45] = "minecraft:brick_block"; + materials[46] = "minecraft:tnt"; + materials[47] = "minecraft:bookshelf"; + materials[48] = "minecraft:mossy_cobblestone"; + materials[49] = "minecraft:obsidian"; + materials[50] = "minecraft:torch"; + materials[51] = "minecraft:fire"; + materials[52] = "minecraft:mob_spawner"; + materials[53] = "minecraft:oak_stairs"; + materials[54] = "minecraft:chest"; + materials[56] = "minecraft:diamond_ore"; + materials[57] = "minecraft:diamond_block"; + materials[58] = "minecraft:crafting_table"; + materials[60] = "minecraft:farmland"; + materials[61] = "minecraft:furnace"; + materials[62] = "minecraft:lit_furnace"; + materials[65] = "minecraft:ladder"; + materials[66] = "minecraft:rail"; + materials[67] = "minecraft:stone_stairs"; + materials[69] = "minecraft:lever"; + materials[70] = "minecraft:stone_pressure_plate"; + materials[72] = "minecraft:wooden_pressure_plate"; + materials[73] = "minecraft:redstone_ore"; + materials[76] = "minecraft:redstone_torch"; + materials[77] = "minecraft:stone_button"; + materials[78] = "minecraft:snow_layer"; + materials[79] = "minecraft:ice"; + materials[80] = "minecraft:snow"; + materials[81] = "minecraft:cactus"; + materials[82] = "minecraft:clay"; + materials[84] = "minecraft:jukebox"; + materials[85] = "minecraft:fence"; + materials[86] = "minecraft:pumpkin"; + materials[87] = "minecraft:netherrack"; + materials[88] = "minecraft:soul_sand"; + materials[89] = "minecraft:glowstone"; + materials[90] = "minecraft:portal"; + materials[91] = "minecraft:lit_pumpkin"; + materials[95] = "minecraft:stained_glass"; + materials[96] = "minecraft:trapdoor"; + materials[97] = "minecraft:monster_egg"; + materials[98] = "minecraft:stonebrick"; + materials[99] = "minecraft:brown_mushroom_block"; + materials[100] = "minecraft:red_mushroom_block"; + materials[101] = "minecraft:iron_bars"; + materials[102] = "minecraft:glass_pane"; + materials[103] = "minecraft:melon_block"; + materials[106] = "minecraft:vine"; + materials[107] = "minecraft:fence_gate"; + materials[108] = "minecraft:brick_stairs"; + materials[109] = "minecraft:stone_brick_stairs"; + materials[110] = "minecraft:mycelium"; + materials[111] = "minecraft:waterlily"; + materials[112] = "minecraft:nether_brick"; + materials[113] = "minecraft:nether_brick_fence"; + materials[114] = "minecraft:nether_brick_stairs"; + materials[116] = "minecraft:enchanting_table"; + materials[119] = "minecraft:end_portal"; + materials[120] = "minecraft:end_portal_frame"; + materials[121] = "minecraft:end_stone"; + materials[122] = "minecraft:dragon_egg"; + materials[123] = "minecraft:redstone_lamp"; + materials[125] = "minecraft:double_wooden_slab"; + materials[126] = "minecraft:wooden_slab"; + materials[127] = "minecraft:cocoa"; + materials[128] = "minecraft:sandstone_stairs"; + materials[129] = "minecraft:emerald_ore"; + materials[130] = "minecraft:ender_chest"; + materials[131] = "minecraft:tripwire_hook"; + materials[133] = "minecraft:emerald_block"; + materials[134] = "minecraft:spruce_stairs"; + materials[135] = "minecraft:birch_stairs"; + materials[136] = "minecraft:jungle_stairs"; + materials[137] = "minecraft:command_block"; + materials[138] = "minecraft:beacon"; + materials[139] = "minecraft:cobblestone_wall"; + materials[141] = "minecraft:carrots"; + materials[142] = "minecraft:potatoes"; + materials[143] = "minecraft:wooden_button"; + materials[145] = "minecraft:anvil"; + materials[146] = "minecraft:trapped_chest"; + materials[147] = "minecraft:light_weighted_pressure_plate"; + materials[148] = "minecraft:heavy_weighted_pressure_plate"; + materials[151] = "minecraft:daylight_detector"; + materials[152] = "minecraft:redstone_block"; + materials[153] = "minecraft:quartz_ore"; + materials[154] = "minecraft:hopper"; + materials[155] = "minecraft:quartz_block"; + materials[156] = "minecraft:quartz_stairs"; + materials[157] = "minecraft:activator_rail"; + materials[158] = "minecraft:dropper"; + materials[159] = "minecraft:stained_hardened_clay"; + materials[160] = "minecraft:stained_glass_pane"; + materials[161] = "minecraft:leaves2"; + materials[162] = "minecraft:log2"; + materials[163] = "minecraft:acacia_stairs"; + materials[164] = "minecraft:dark_oak_stairs"; + materials[170] = "minecraft:hay_block"; + materials[171] = "minecraft:carpet"; + materials[172] = "minecraft:hardened_clay"; + materials[173] = "minecraft:coal_block"; + materials[174] = "minecraft:packed_ice"; + materials[175] = "minecraft:double_plant"; + materials[256] = "minecraft:iron_shovel"; + materials[257] = "minecraft:iron_pickaxe"; + materials[258] = "minecraft:iron_axe"; + materials[259] = "minecraft:flint_and_steel"; + materials[260] = "minecraft:apple"; + materials[261] = "minecraft:bow"; + materials[262] = "minecraft:arrow"; + materials[263] = "minecraft:coal"; + materials[264] = "minecraft:diamond"; + materials[265] = "minecraft:iron_ingot"; + materials[266] = "minecraft:gold_ingot"; + materials[267] = "minecraft:iron_sword"; + materials[268] = "minecraft:wooden_sword"; + materials[269] = "minecraft:wooden_shovel"; + materials[270] = "minecraft:wooden_pickaxe"; + materials[271] = "minecraft:wooden_axe"; + materials[272] = "minecraft:stone_sword"; + materials[273] = "minecraft:stone_shovel"; + materials[274] = "minecraft:stone_pickaxe"; + materials[275] = "minecraft:stone_axe"; + materials[276] = "minecraft:diamond_sword"; + materials[277] = "minecraft:diamond_shovel"; + materials[278] = "minecraft:diamond_pickaxe"; + materials[279] = "minecraft:diamond_axe"; + materials[280] = "minecraft:stick"; + materials[281] = "minecraft:bowl"; + materials[282] = "minecraft:mushroom_stew"; + materials[283] = "minecraft:golden_sword"; + materials[284] = "minecraft:golden_shovel"; + materials[285] = "minecraft:golden_pickaxe"; + materials[286] = "minecraft:golden_axe"; + materials[287] = "minecraft:string"; + materials[288] = "minecraft:feather"; + materials[289] = "minecraft:gunpowder"; + materials[290] = "minecraft:wooden_hoe"; + materials[291] = "minecraft:stone_hoe"; + materials[292] = "minecraft:iron_hoe"; + materials[293] = "minecraft:diamond_hoe"; + materials[294] = "minecraft:golden_hoe"; + materials[295] = "minecraft:wheat_seeds"; + materials[296] = "minecraft:wheat"; + materials[297] = "minecraft:bread"; + materials[298] = "minecraft:leather_helmet"; + materials[299] = "minecraft:leather_chestplate"; + materials[300] = "minecraft:leather_leggings"; + materials[301] = "minecraft:leather_boots"; + materials[302] = "minecraft:chainmail_helmet"; + materials[303] = "minecraft:chainmail_chestplate"; + materials[304] = "minecraft:chainmail_leggings"; + materials[305] = "minecraft:chainmail_boots"; + materials[306] = "minecraft:iron_helmet"; + materials[307] = "minecraft:iron_chestplate"; + materials[308] = "minecraft:iron_leggings"; + materials[309] = "minecraft:iron_boots"; + materials[310] = "minecraft:diamond_helmet"; + materials[311] = "minecraft:diamond_chestplate"; + materials[312] = "minecraft:diamond_leggings"; + materials[313] = "minecraft:diamond_boots"; + materials[314] = "minecraft:golden_helmet"; + materials[315] = "minecraft:golden_chestplate"; + materials[316] = "minecraft:golden_leggings"; + materials[317] = "minecraft:golden_boots"; + materials[318] = "minecraft:flint"; + materials[319] = "minecraft:porkchop"; + materials[320] = "minecraft:cooked_porkchop"; + materials[321] = "minecraft:painting"; + materials[322] = "minecraft:golden_apple"; + materials[323] = "minecraft:sign"; + materials[324] = "minecraft:wooden_door"; + materials[325] = "minecraft:bucket"; + materials[326] = "minecraft:water_bucket"; + materials[327] = "minecraft:lava_bucket"; + materials[328] = "minecraft:minecart"; + materials[329] = "minecraft:saddle"; + materials[330] = "minecraft:iron_door"; + materials[331] = "minecraft:redstone"; + materials[332] = "minecraft:snowball"; + materials[333] = "minecraft:boat"; + materials[334] = "minecraft:leather"; + materials[335] = "minecraft:milk_bucket"; + materials[336] = "minecraft:brick"; + materials[337] = "minecraft:clay_ball"; + materials[338] = "minecraft:reeds"; + materials[339] = "minecraft:paper"; + materials[340] = "minecraft:book"; + materials[341] = "minecraft:slime_ball"; + materials[342] = "minecraft:chest_minecart"; + materials[343] = "minecraft:furnace_minecart"; + materials[344] = "minecraft:egg"; + materials[345] = "minecraft:compass"; + materials[346] = "minecraft:fishing_rod"; + materials[347] = "minecraft:clock"; + materials[348] = "minecraft:glowstone_dust"; + materials[349] = "minecraft:fish"; + materials[350] = "minecraft:cooked_fish"; // Paper - cooked_fished -> cooked_fish + materials[351] = "minecraft:dye"; + materials[352] = "minecraft:bone"; + materials[353] = "minecraft:sugar"; + materials[354] = "minecraft:cake"; + materials[355] = "minecraft:bed"; + materials[356] = "minecraft:repeater"; + materials[357] = "minecraft:cookie"; + materials[358] = "minecraft:filled_map"; + materials[359] = "minecraft:shears"; + materials[360] = "minecraft:melon"; + materials[361] = "minecraft:pumpkin_seeds"; + materials[362] = "minecraft:melon_seeds"; + materials[363] = "minecraft:beef"; + materials[364] = "minecraft:cooked_beef"; + materials[365] = "minecraft:chicken"; + materials[366] = "minecraft:cooked_chicken"; + materials[367] = "minecraft:rotten_flesh"; + materials[368] = "minecraft:ender_pearl"; + materials[369] = "minecraft:blaze_rod"; + materials[370] = "minecraft:ghast_tear"; + materials[371] = "minecraft:gold_nugget"; + materials[372] = "minecraft:nether_wart"; + materials[373] = "minecraft:potion"; + materials[374] = "minecraft:glass_bottle"; + materials[375] = "minecraft:spider_eye"; + materials[376] = "minecraft:fermented_spider_eye"; + materials[377] = "minecraft:blaze_powder"; + materials[378] = "minecraft:magma_cream"; + materials[379] = "minecraft:brewing_stand"; + materials[380] = "minecraft:cauldron"; + materials[381] = "minecraft:ender_eye"; + materials[382] = "minecraft:speckled_melon"; + materials[383] = "minecraft:spawn_egg"; + materials[384] = "minecraft:experience_bottle"; + materials[385] = "minecraft:fire_charge"; + materials[386] = "minecraft:writable_book"; + materials[387] = "minecraft:written_book"; + materials[388] = "minecraft:emerald"; + materials[389] = "minecraft:item_frame"; + materials[390] = "minecraft:flower_pot"; + materials[391] = "minecraft:carrot"; + materials[392] = "minecraft:potato"; + materials[393] = "minecraft:baked_potato"; + materials[394] = "minecraft:poisonous_potato"; + materials[395] = "minecraft:map"; + materials[396] = "minecraft:golden_carrot"; + materials[397] = "minecraft:skull"; + materials[398] = "minecraft:carrot_on_a_stick"; + materials[399] = "minecraft:nether_star"; + materials[400] = "minecraft:pumpkin_pie"; + materials[401] = "minecraft:fireworks"; + materials[402] = "minecraft:firework_charge"; + materials[403] = "minecraft:enchanted_book"; + materials[404] = "minecraft:comparator"; + materials[405] = "minecraft:netherbrick"; + materials[406] = "minecraft:quartz"; + materials[407] = "minecraft:tnt_minecart"; + materials[408] = "minecraft:hopper_minecart"; + materials[417] = "minecraft:iron_horse_armor"; + materials[418] = "minecraft:golden_horse_armor"; + materials[419] = "minecraft:diamond_horse_armor"; + materials[420] = "minecraft:lead"; + materials[421] = "minecraft:name_tag"; + materials[422] = "minecraft:command_block_minecart"; + materials[2256] = "minecraft:record_13"; + materials[2257] = "minecraft:record_cat"; + materials[2258] = "minecraft:record_blocks"; + materials[2259] = "minecraft:record_chirp"; + materials[2260] = "minecraft:record_far"; + materials[2261] = "minecraft:record_mall"; + materials[2262] = "minecraft:record_mellohi"; + materials[2263] = "minecraft:record_stal"; + materials[2264] = "minecraft:record_strad"; + materials[2265] = "minecraft:record_ward"; + materials[2266] = "minecraft:record_11"; + materials[2267] = "minecraft:record_wait"; + } + } + + private static class DataConverterArmorStand implements DataConverter { + + DataConverterArmorStand() {} + + public int getDataVersion() { + return 147; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("ArmorStand".equals(cmp.getString("id")) && cmp.getBoolean("Silent") && !cmp.getBoolean("Marker")) { + cmp.remove("Silent"); + } + + return cmp; + } + } + + private static class DataConverterBanner implements DataConverter { + + DataConverterBanner() {} + + public int getDataVersion() { + return 804; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:banner".equals(cmp.getString("id")) && cmp.containsKey("tag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.containsKey("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.containsKey("Base", 99)) { + cmp.putShort("Damage", (short) (nbttagcompound2.getShort("Base") & 15)); + if (nbttagcompound1.containsKey("display", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound1.getCompound("display"); + + if (nbttagcompound3.containsKey("Lore", 9)) { + ListTag nbttaglist = nbttagcompound3.getList("Lore", 8); + + if (nbttaglist.size() == 1 && "(+NBT)".equals(nbttaglist.getString(0))) { + return cmp; + } + } + } + + nbttagcompound2.remove("Base"); + if (nbttagcompound2.isEmpty()) { + nbttagcompound1.remove("BlockEntityTag"); + } + + if (nbttagcompound1.isEmpty()) { + cmp.remove("tag"); + } + } + } + } + + return cmp; + } + } + + private static class DataConverterPotionId implements DataConverter { + + private static final String[] potions = new String[128]; + + DataConverterPotionId() {} + + public int getDataVersion() { + return 102; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:potion".equals(cmp.getString("id"))) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + short short0 = cmp.getShort("Damage"); + + if (!nbttagcompound1.containsKey("Potion", 8)) { + String s = DataConverterPotionId.potions[short0 & 127]; + + nbttagcompound1.putString("Potion", s == null ? "minecraft:water" : s); + cmp.put("tag", nbttagcompound1); + if ((short0 & 16384) == 16384) { + cmp.putString("id", "minecraft:splash_potion"); + } + } + + if (short0 != 0) { + cmp.putShort("Damage", (short) 0); + } + } + + return cmp; + } + + static { + DataConverterPotionId.potions[0] = "minecraft:water"; + DataConverterPotionId.potions[1] = "minecraft:regeneration"; + DataConverterPotionId.potions[2] = "minecraft:swiftness"; + DataConverterPotionId.potions[3] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[4] = "minecraft:poison"; + DataConverterPotionId.potions[5] = "minecraft:healing"; + DataConverterPotionId.potions[6] = "minecraft:night_vision"; + DataConverterPotionId.potions[7] = null; + DataConverterPotionId.potions[8] = "minecraft:weakness"; + DataConverterPotionId.potions[9] = "minecraft:strength"; + DataConverterPotionId.potions[10] = "minecraft:slowness"; + DataConverterPotionId.potions[11] = "minecraft:leaping"; + DataConverterPotionId.potions[12] = "minecraft:harming"; + DataConverterPotionId.potions[13] = "minecraft:water_breathing"; + DataConverterPotionId.potions[14] = "minecraft:invisibility"; + DataConverterPotionId.potions[15] = null; + DataConverterPotionId.potions[16] = "minecraft:awkward"; + DataConverterPotionId.potions[17] = "minecraft:regeneration"; + DataConverterPotionId.potions[18] = "minecraft:swiftness"; + DataConverterPotionId.potions[19] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[20] = "minecraft:poison"; + DataConverterPotionId.potions[21] = "minecraft:healing"; + DataConverterPotionId.potions[22] = "minecraft:night_vision"; + DataConverterPotionId.potions[23] = null; + DataConverterPotionId.potions[24] = "minecraft:weakness"; + DataConverterPotionId.potions[25] = "minecraft:strength"; + DataConverterPotionId.potions[26] = "minecraft:slowness"; + DataConverterPotionId.potions[27] = "minecraft:leaping"; + DataConverterPotionId.potions[28] = "minecraft:harming"; + DataConverterPotionId.potions[29] = "minecraft:water_breathing"; + DataConverterPotionId.potions[30] = "minecraft:invisibility"; + DataConverterPotionId.potions[31] = null; + DataConverterPotionId.potions[32] = "minecraft:thick"; + DataConverterPotionId.potions[33] = "minecraft:strong_regeneration"; + DataConverterPotionId.potions[34] = "minecraft:strong_swiftness"; + DataConverterPotionId.potions[35] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[36] = "minecraft:strong_poison"; + DataConverterPotionId.potions[37] = "minecraft:strong_healing"; + DataConverterPotionId.potions[38] = "minecraft:night_vision"; + DataConverterPotionId.potions[39] = null; + DataConverterPotionId.potions[40] = "minecraft:weakness"; + DataConverterPotionId.potions[41] = "minecraft:strong_strength"; + DataConverterPotionId.potions[42] = "minecraft:slowness"; + DataConverterPotionId.potions[43] = "minecraft:strong_leaping"; + DataConverterPotionId.potions[44] = "minecraft:strong_harming"; + DataConverterPotionId.potions[45] = "minecraft:water_breathing"; + DataConverterPotionId.potions[46] = "minecraft:invisibility"; + DataConverterPotionId.potions[47] = null; + DataConverterPotionId.potions[48] = null; + DataConverterPotionId.potions[49] = "minecraft:strong_regeneration"; + DataConverterPotionId.potions[50] = "minecraft:strong_swiftness"; + DataConverterPotionId.potions[51] = "minecraft:fire_resistance"; + DataConverterPotionId.potions[52] = "minecraft:strong_poison"; + DataConverterPotionId.potions[53] = "minecraft:strong_healing"; + DataConverterPotionId.potions[54] = "minecraft:night_vision"; + DataConverterPotionId.potions[55] = null; + DataConverterPotionId.potions[56] = "minecraft:weakness"; + DataConverterPotionId.potions[57] = "minecraft:strong_strength"; + DataConverterPotionId.potions[58] = "minecraft:slowness"; + DataConverterPotionId.potions[59] = "minecraft:strong_leaping"; + DataConverterPotionId.potions[60] = "minecraft:strong_harming"; + DataConverterPotionId.potions[61] = "minecraft:water_breathing"; + DataConverterPotionId.potions[62] = "minecraft:invisibility"; + DataConverterPotionId.potions[63] = null; + DataConverterPotionId.potions[64] = "minecraft:mundane"; + DataConverterPotionId.potions[65] = "minecraft:long_regeneration"; + DataConverterPotionId.potions[66] = "minecraft:long_swiftness"; + DataConverterPotionId.potions[67] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[68] = "minecraft:long_poison"; + DataConverterPotionId.potions[69] = "minecraft:healing"; + DataConverterPotionId.potions[70] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[71] = null; + DataConverterPotionId.potions[72] = "minecraft:long_weakness"; + DataConverterPotionId.potions[73] = "minecraft:long_strength"; + DataConverterPotionId.potions[74] = "minecraft:long_slowness"; + DataConverterPotionId.potions[75] = "minecraft:long_leaping"; + DataConverterPotionId.potions[76] = "minecraft:harming"; + DataConverterPotionId.potions[77] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[78] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[79] = null; + DataConverterPotionId.potions[80] = "minecraft:awkward"; + DataConverterPotionId.potions[81] = "minecraft:long_regeneration"; + DataConverterPotionId.potions[82] = "minecraft:long_swiftness"; + DataConverterPotionId.potions[83] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[84] = "minecraft:long_poison"; + DataConverterPotionId.potions[85] = "minecraft:healing"; + DataConverterPotionId.potions[86] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[87] = null; + DataConverterPotionId.potions[88] = "minecraft:long_weakness"; + DataConverterPotionId.potions[89] = "minecraft:long_strength"; + DataConverterPotionId.potions[90] = "minecraft:long_slowness"; + DataConverterPotionId.potions[91] = "minecraft:long_leaping"; + DataConverterPotionId.potions[92] = "minecraft:harming"; + DataConverterPotionId.potions[93] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[94] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[95] = null; + DataConverterPotionId.potions[96] = "minecraft:thick"; + DataConverterPotionId.potions[97] = "minecraft:regeneration"; + DataConverterPotionId.potions[98] = "minecraft:swiftness"; + DataConverterPotionId.potions[99] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[100] = "minecraft:poison"; + DataConverterPotionId.potions[101] = "minecraft:strong_healing"; + DataConverterPotionId.potions[102] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[103] = null; + DataConverterPotionId.potions[104] = "minecraft:long_weakness"; + DataConverterPotionId.potions[105] = "minecraft:strength"; + DataConverterPotionId.potions[106] = "minecraft:long_slowness"; + DataConverterPotionId.potions[107] = "minecraft:leaping"; + DataConverterPotionId.potions[108] = "minecraft:strong_harming"; + DataConverterPotionId.potions[109] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[110] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[111] = null; + DataConverterPotionId.potions[112] = null; + DataConverterPotionId.potions[113] = "minecraft:regeneration"; + DataConverterPotionId.potions[114] = "minecraft:swiftness"; + DataConverterPotionId.potions[115] = "minecraft:long_fire_resistance"; + DataConverterPotionId.potions[116] = "minecraft:poison"; + DataConverterPotionId.potions[117] = "minecraft:strong_healing"; + DataConverterPotionId.potions[118] = "minecraft:long_night_vision"; + DataConverterPotionId.potions[119] = null; + DataConverterPotionId.potions[120] = "minecraft:long_weakness"; + DataConverterPotionId.potions[121] = "minecraft:strength"; + DataConverterPotionId.potions[122] = "minecraft:long_slowness"; + DataConverterPotionId.potions[123] = "minecraft:leaping"; + DataConverterPotionId.potions[124] = "minecraft:strong_harming"; + DataConverterPotionId.potions[125] = "minecraft:long_water_breathing"; + DataConverterPotionId.potions[126] = "minecraft:long_invisibility"; + DataConverterPotionId.potions[127] = null; + } + } + + private static class DataConverterSpawnEgg implements DataConverter { + + private static final String[] eggs = new String[256]; + + DataConverterSpawnEgg() {} + + public int getDataVersion() { + return 105; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:spawn_egg".equals(cmp.getString("id"))) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("EntityTag"); + short short0 = cmp.getShort("Damage"); + + if (!nbttagcompound2.containsKey("id", 8)) { + String s = DataConverterSpawnEgg.eggs[short0 & 255]; + + if (s != null) { + nbttagcompound2.putString("id", s); + nbttagcompound1.put("EntityTag", nbttagcompound2); + cmp.put("tag", nbttagcompound1); + } + } + + if (short0 != 0) { + cmp.putShort("Damage", (short) 0); + } + } + + return cmp; + } + + static { + + DataConverterSpawnEgg.eggs[1] = "Item"; + DataConverterSpawnEgg.eggs[2] = "XPOrb"; + DataConverterSpawnEgg.eggs[7] = "ThrownEgg"; + DataConverterSpawnEgg.eggs[8] = "LeashKnot"; + DataConverterSpawnEgg.eggs[9] = "Painting"; + DataConverterSpawnEgg.eggs[10] = "Arrow"; + DataConverterSpawnEgg.eggs[11] = "Snowball"; + DataConverterSpawnEgg.eggs[12] = "Fireball"; + DataConverterSpawnEgg.eggs[13] = "SmallFireball"; + DataConverterSpawnEgg.eggs[14] = "ThrownEnderpearl"; + DataConverterSpawnEgg.eggs[15] = "EyeOfEnderSignal"; + DataConverterSpawnEgg.eggs[16] = "ThrownPotion"; + DataConverterSpawnEgg.eggs[17] = "ThrownExpBottle"; + DataConverterSpawnEgg.eggs[18] = "ItemFrame"; + DataConverterSpawnEgg.eggs[19] = "WitherSkull"; + DataConverterSpawnEgg.eggs[20] = "PrimedTnt"; + DataConverterSpawnEgg.eggs[21] = "FallingSand"; + DataConverterSpawnEgg.eggs[22] = "FireworksRocketEntity"; + DataConverterSpawnEgg.eggs[23] = "TippedArrow"; + DataConverterSpawnEgg.eggs[24] = "SpectralArrow"; + DataConverterSpawnEgg.eggs[25] = "ShulkerBullet"; + DataConverterSpawnEgg.eggs[26] = "DragonFireball"; + DataConverterSpawnEgg.eggs[30] = "ArmorStand"; + DataConverterSpawnEgg.eggs[41] = "Boat"; + DataConverterSpawnEgg.eggs[42] = "MinecartRideable"; + DataConverterSpawnEgg.eggs[43] = "MinecartChest"; + DataConverterSpawnEgg.eggs[44] = "MinecartFurnace"; + DataConverterSpawnEgg.eggs[45] = "MinecartTNT"; + DataConverterSpawnEgg.eggs[46] = "MinecartHopper"; + DataConverterSpawnEgg.eggs[47] = "MinecartSpawner"; + DataConverterSpawnEgg.eggs[40] = "MinecartCommandBlock"; + DataConverterSpawnEgg.eggs[48] = "Mob"; + DataConverterSpawnEgg.eggs[49] = "Monster"; + DataConverterSpawnEgg.eggs[50] = "Creeper"; + DataConverterSpawnEgg.eggs[51] = "Skeleton"; + DataConverterSpawnEgg.eggs[52] = "Spider"; + DataConverterSpawnEgg.eggs[53] = "Giant"; + DataConverterSpawnEgg.eggs[54] = "Zombie"; + DataConverterSpawnEgg.eggs[55] = "Slime"; + DataConverterSpawnEgg.eggs[56] = "Ghast"; + DataConverterSpawnEgg.eggs[57] = "PigZombie"; + DataConverterSpawnEgg.eggs[58] = "Enderman"; + DataConverterSpawnEgg.eggs[59] = "CaveSpider"; + DataConverterSpawnEgg.eggs[60] = "Silverfish"; + DataConverterSpawnEgg.eggs[61] = "Blaze"; + DataConverterSpawnEgg.eggs[62] = "LavaSlime"; + DataConverterSpawnEgg.eggs[63] = "EnderDragon"; + DataConverterSpawnEgg.eggs[64] = "WitherBoss"; + DataConverterSpawnEgg.eggs[65] = "Bat"; + DataConverterSpawnEgg.eggs[66] = "Witch"; + DataConverterSpawnEgg.eggs[67] = "Endermite"; + DataConverterSpawnEgg.eggs[68] = "Guardian"; + DataConverterSpawnEgg.eggs[69] = "Shulker"; + DataConverterSpawnEgg.eggs[90] = "Pig"; + DataConverterSpawnEgg.eggs[91] = "Sheep"; + DataConverterSpawnEgg.eggs[92] = "Cow"; + DataConverterSpawnEgg.eggs[93] = "Chicken"; + DataConverterSpawnEgg.eggs[94] = "Squid"; + DataConverterSpawnEgg.eggs[95] = "Wolf"; + DataConverterSpawnEgg.eggs[96] = "MushroomCow"; + DataConverterSpawnEgg.eggs[97] = "SnowMan"; + DataConverterSpawnEgg.eggs[98] = "Ozelot"; + DataConverterSpawnEgg.eggs[99] = "VillagerGolem"; + DataConverterSpawnEgg.eggs[100] = "EntityHorse"; + DataConverterSpawnEgg.eggs[101] = "Rabbit"; + DataConverterSpawnEgg.eggs[120] = "Villager"; + DataConverterSpawnEgg.eggs[200] = "EnderCrystal"; + } + } + + private static class DataConverterMinecart implements DataConverter { + + private static final List a = Lists.newArrayList(new String[] { "MinecartRideable", "MinecartChest", "MinecartFurnace", "MinecartTNT", "MinecartSpawner", "MinecartHopper", "MinecartCommandBlock"}); + + DataConverterMinecart() {} + + public int getDataVersion() { + return 106; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Minecart".equals(cmp.getString("id"))) { + String s = "MinecartRideable"; + int i = cmp.getInt("Type"); + + if (i > 0 && i < DataConverterMinecart.a.size()) { + s = DataConverterMinecart.a.get(i); + } + + cmp.putString("id", s); + cmp.remove("Type"); + } + + return cmp; + } + } + + private static class DataConverterMobSpawner implements DataConverter { + + DataConverterMobSpawner() {} + + public int getDataVersion() { + return 107; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (!"MobSpawner".equals(cmp.getString("id"))) { + return cmp; + } else { + if (cmp.containsKey("EntityId", 8)) { + String s = cmp.getString("EntityId"); + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("SpawnData"); + + nbttagcompound1.putString("id", s.isEmpty() ? "Pig" : s); + cmp.put("SpawnData", nbttagcompound1); + cmp.remove("EntityId"); + } + + if (cmp.containsKey("SpawnPotentials", 9)) { + ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int i = 0; i < nbttaglist.size(); ++i) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompoundTag(i); + + if (nbttagcompound2.containsKey("Type", 8)) { + net.minecraft.nbt.CompoundTag nbttagcompound3 = nbttagcompound2.getCompound("Properties"); + + nbttagcompound3.putString("id", nbttagcompound2.getString("Type")); + nbttagcompound2.put("Entity", nbttagcompound3); + nbttagcompound2.remove("Type"); + nbttagcompound2.remove("Properties"); + } + } + } + + return cmp; + } + } + } + + private static class DataConverterUUID implements DataConverter { + + DataConverterUUID() {} + + public int getDataVersion() { + return 108; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.containsKey("UUID", 8)) { + cmp.putUuid("UUID", UUID.fromString(cmp.getString("UUID"))); + } + + return cmp; + } + } + + private static class DataConverterHealth implements DataConverter { + + private static final Set a = Sets.newHashSet("ArmorStand", "Bat", "Blaze", "CaveSpider", "Chicken", "Cow", "Creeper", "EnderDragon", "Enderman", "Endermite", "EntityHorse", "Ghast", "Giant", "Guardian", "LavaSlime", "MushroomCow", "Ozelot", "Pig", "PigZombie", "Rabbit", "Sheep", "Shulker", "Silverfish", "Skeleton", "Slime", "SnowMan", "Spider", "Squid", "Villager", "VillagerGolem", "Witch", "WitherBoss", "Wolf", "Zombie"); + + DataConverterHealth() {} + + public int getDataVersion() { + return 109; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (DataConverterHealth.a.contains(cmp.getString("id"))) { + float f; + + if (cmp.containsKey("HealF", 99)) { + f = cmp.getFloat("HealF"); + cmp.remove("HealF"); + } else { + if (!cmp.containsKey("Health", 99)) { + return cmp; + } + + f = cmp.getFloat("Health"); + } + + cmp.putFloat("Health", f); + } + + return cmp; + } + } + + private static class DataConverterSaddle implements DataConverter { + + DataConverterSaddle() {} + + public int getDataVersion() { + return 110; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id")) && !cmp.containsKey("SaddleItem", 10) && cmp.getBoolean("Saddle")) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = new net.minecraft.nbt.CompoundTag(); + + nbttagcompound1.putString("id", "minecraft:saddle"); + nbttagcompound1.putByte("Count", (byte) 1); + nbttagcompound1.putShort("Damage", (short) 0); + cmp.put("SaddleItem", nbttagcompound1); + cmp.remove("Saddle"); + } + + return cmp; + } + } + + private static class DataConverterHanging implements DataConverter { + + DataConverterHanging() {} + + public int getDataVersion() { + return 111; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = cmp.getString("id"); + boolean flag = "Painting".equals(s); + boolean flag1 = "ItemFrame".equals(s); + + if ((flag || flag1) && !cmp.containsKey("Facing", 99)) { + Direction enumdirection; + + if (cmp.containsKey("Direction", 99)) { + enumdirection = Direction.fromHorizontal(cmp.getByte("Direction")); + cmp.putInt("TileX", cmp.getInt("TileX") + enumdirection.getOffsetX()); + cmp.putInt("TileY", cmp.getInt("TileY") + enumdirection.getOffsetY()); + cmp.putInt("TileZ", cmp.getInt("TileZ") + enumdirection.getOffsetZ()); + cmp.remove("Direction"); + if (flag1 && cmp.containsKey("ItemRotation", 99)) { + cmp.putByte("ItemRotation", (byte) (cmp.getByte("ItemRotation") * 2)); + } + } else { + enumdirection = Direction.fromHorizontal(cmp.getByte("Dir")); + cmp.remove("Dir"); + } + + cmp.putByte("Facing", (byte) enumdirection.getHorizontal()); + } + + return cmp; + } + } + + private static class DataConverterDropChances implements DataConverter { + + DataConverterDropChances() {} + + public int getDataVersion() { + return 113; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + ListTag nbttaglist; + + if (cmp.containsKey("HandDropChances", 9)) { + nbttaglist = cmp.getList("HandDropChances", 5); + if (nbttaglist.size() == 2 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F) { + cmp.remove("HandDropChances"); + } + } + + if (cmp.containsKey("ArmorDropChances", 9)) { + nbttaglist = cmp.getList("ArmorDropChances", 5); + if (nbttaglist.size() == 4 && nbttaglist.getFloat(0) == 0.0F && nbttaglist.getFloat(1) == 0.0F && nbttaglist.getFloat(2) == 0.0F && nbttaglist.getFloat(3) == 0.0F) { + cmp.remove("ArmorDropChances"); + } + } + + return cmp; + } + } + + private static class DataConverterRiding implements DataConverter { + + DataConverterRiding() {} + + public int getDataVersion() { + return 135; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + while (cmp.containsKey("Riding", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = this.b(cmp); + + this.convert(cmp, nbttagcompound1); + cmp = nbttagcompound1; + } + + return cmp; + } + + protected void convert(net.minecraft.nbt.CompoundTag nbttagcompound, net.minecraft.nbt.CompoundTag nbttagcompound1) { + ListTag nbttaglist = new ListTag(); + + nbttaglist.add(nbttagcompound); + nbttagcompound1.put("Passengers", nbttaglist); + } + + protected net.minecraft.nbt.CompoundTag b(net.minecraft.nbt.CompoundTag nbttagcompound) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = nbttagcompound.getCompound("Riding"); + + nbttagcompound.remove("Riding"); + return nbttagcompound1; + } + } + + private static class DataConverterBook implements DataConverter { + + DataConverterBook() {} + + public int getDataVersion() { + return 165; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:written_book".equals(cmp.getString("id"))) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.containsKey("pages", 9)) { + ListTag nbttaglist = nbttagcompound1.getList("pages", 8); + + for (int i = 0; i < nbttaglist.size(); ++i) { + String s = nbttaglist.getString(i); + Object object = null; + + if (!"null".equals(s) && !Strings.isNullOrEmpty(s)) { + if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { + object = new TextComponent(s); + } else { + try { + object = JsonHelper.deserialize(DataConverterSignText.a, s, Component.class, true); + if (object == null) { + object = new TextComponent(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonString(s); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromLenientJsonString(s); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = new TextComponent(s); + } + } + } else { + object = new TextComponent(""); + } + + nbttaglist.set(i, new StringTag(Component.Serializer.toJsonString((Component) object))); + } + + nbttagcompound1.put("pages", nbttaglist); + } + } + + return cmp; + } + } + + private static class DataConverterCookedFish implements DataConverter { + + private static final Identifier a = new Identifier("cooked_fished"); + + DataConverterCookedFish() {} + + public int getDataVersion() { + return 502; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.containsKey("id", 8) && DataConverterCookedFish.a.equals(new Identifier(cmp.getString("id")))) { + cmp.putString("id", "minecraft:cooked_fish"); + } + + return cmp; + } + } + + private static class DataConverterZombie implements DataConverter { + + private static final Random a = new Random(); + + DataConverterZombie() {} + + public int getDataVersion() { + return 502; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Zombie".equals(cmp.getString("id")) && cmp.getBoolean("IsVillager")) { + if (!cmp.containsKey("ZombieType", 99)) { + int i = -1; + + if (cmp.containsKey("VillagerProfession", 99)) { + try { + i = this.convert(cmp.getInt("VillagerProfession")); + } catch (RuntimeException runtimeexception) { + ; + } + } + + if (i == -1) { + i = this.convert(DataConverterZombie.a.nextInt(6)); + } + + cmp.putInt("ZombieType", i); + } + + cmp.remove("IsVillager"); + } + + return cmp; + } + + private int convert(int i) { + return i >= 0 && i < 6 ? i : -1; + } + } + + private static class DataConverterVBO implements DataConverter { + + DataConverterVBO() {} + + public int getDataVersion() { + return 505; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + cmp.putString("useVbo", "true"); + return cmp; + } + } + + private static class DataConverterGuardian implements DataConverter { + + DataConverterGuardian() {} + + public int getDataVersion() { + return 700; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Guardian".equals(cmp.getString("id"))) { + if (cmp.getBoolean("Elder")) { + cmp.putString("id", "ElderGuardian"); + } + + cmp.remove("Elder"); + } + + return cmp; + } + } + + private static class DataConverterSkeleton implements DataConverter { + + DataConverterSkeleton() {} + + public int getDataVersion() { + return 701; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = cmp.getString("id"); + + if ("Skeleton".equals(s)) { + int i = cmp.getInt("SkeletonType"); + + if (i == 1) { + cmp.putString("id", "WitherSkeleton"); + } else if (i == 2) { + cmp.putString("id", "Stray"); + } + + cmp.remove("SkeletonType"); + } + + return cmp; + } + } + + private static class DataConverterZombieType implements DataConverter { + + DataConverterZombieType() {} + + public int getDataVersion() { + return 702; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Zombie".equals(cmp.getString("id"))) { + int i = cmp.getInt("ZombieType"); + + switch (i) { + case 1: + case 2: + case 3: + case 4: + case 5: + cmp.putString("id", "ZombieVillager"); + cmp.putInt("Profession", i - 1); + break; + case 6: + cmp.putString("id", "Husk"); + case 0: + default: + break; + } + + cmp.remove("ZombieType"); + } + + return cmp; + } + } + + private static class DataConverterHorse implements DataConverter { + + DataConverterHorse() {} + + public int getDataVersion() { + return 703; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("EntityHorse".equals(cmp.getString("id"))) { + int i = cmp.getInt("Type"); + + switch (i) { + case 1: + cmp.putString("id", "Donkey"); + break; + + case 2: + cmp.putString("id", "Mule"); + break; + + case 3: + cmp.putString("id", "ZombieHorse"); + break; + + case 4: + cmp.putString("id", "SkeletonHorse"); + break; + + case 0: + default: + cmp.putString("id", "Horse"); + break; + } + + cmp.remove("Type"); + } + + return cmp; + } + } + + private static class DataConverterTileEntity implements DataConverter { + + private static final Map a = Maps.newHashMap(); + + DataConverterTileEntity() {} + + public int getDataVersion() { + return 704; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = DataConverterTileEntity.a.get(cmp.getString("id")); + + if (s != null) { + cmp.putString("id", s); + } + + return cmp; + } + + static { + DataConverterTileEntity.a.put("Airportal", "minecraft:end_portal"); + DataConverterTileEntity.a.put("Banner", "minecraft:banner"); + DataConverterTileEntity.a.put("Beacon", "minecraft:beacon"); + DataConverterTileEntity.a.put("Cauldron", "minecraft:brewing_stand"); + DataConverterTileEntity.a.put("Chest", "minecraft:chest"); + DataConverterTileEntity.a.put("Comparator", "minecraft:comparator"); + DataConverterTileEntity.a.put("Control", "minecraft:command_block"); + DataConverterTileEntity.a.put("DLDetector", "minecraft:daylight_detector"); + DataConverterTileEntity.a.put("Dropper", "minecraft:dropper"); + DataConverterTileEntity.a.put("EnchantTable", "minecraft:enchanting_table"); + DataConverterTileEntity.a.put("EndGateway", "minecraft:end_gateway"); + DataConverterTileEntity.a.put("EnderChest", "minecraft:ender_chest"); + DataConverterTileEntity.a.put("FlowerPot", "minecraft:flower_pot"); + DataConverterTileEntity.a.put("Furnace", "minecraft:furnace"); + DataConverterTileEntity.a.put("Hopper", "minecraft:hopper"); + DataConverterTileEntity.a.put("MobSpawner", "minecraft:mob_spawner"); + DataConverterTileEntity.a.put("Music", "minecraft:noteblock"); + DataConverterTileEntity.a.put("Piston", "minecraft:piston"); + DataConverterTileEntity.a.put("RecordPlayer", "minecraft:jukebox"); + DataConverterTileEntity.a.put("Sign", "minecraft:sign"); + DataConverterTileEntity.a.put("Skull", "minecraft:skull"); + DataConverterTileEntity.a.put("Structure", "minecraft:structure_block"); + DataConverterTileEntity.a.put("Trap", "minecraft:dispenser"); + } + } + + private static class DataConverterEntity implements DataConverter { + + private static final Map a = Maps.newHashMap(); + + DataConverterEntity() {} + + public int getDataVersion() { + return 704; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = DataConverterEntity.a.get(cmp.getString("id")); + + if (s != null) { + cmp.putString("id", s); + } + + return cmp; + } + + static { + DataConverterEntity.a.put("AreaEffectCloud", "minecraft:area_effect_cloud"); + DataConverterEntity.a.put("ArmorStand", "minecraft:armor_stand"); + DataConverterEntity.a.put("Arrow", "minecraft:arrow"); + DataConverterEntity.a.put("Bat", "minecraft:bat"); + DataConverterEntity.a.put("Blaze", "minecraft:blaze"); + DataConverterEntity.a.put("Boat", "minecraft:boat"); + DataConverterEntity.a.put("CaveSpider", "minecraft:cave_spider"); + DataConverterEntity.a.put("Chicken", "minecraft:chicken"); + DataConverterEntity.a.put("Cow", "minecraft:cow"); + DataConverterEntity.a.put("Creeper", "minecraft:creeper"); + DataConverterEntity.a.put("Donkey", "minecraft:donkey"); + DataConverterEntity.a.put("DragonFireball", "minecraft:dragon_fireball"); + DataConverterEntity.a.put("ElderGuardian", "minecraft:elder_guardian"); + DataConverterEntity.a.put("EnderCrystal", "minecraft:ender_crystal"); + DataConverterEntity.a.put("EnderDragon", "minecraft:ender_dragon"); + DataConverterEntity.a.put("Enderman", "minecraft:enderman"); + DataConverterEntity.a.put("Endermite", "minecraft:endermite"); + DataConverterEntity.a.put("EyeOfEnderSignal", "minecraft:eye_of_ender_signal"); + DataConverterEntity.a.put("FallingSand", "minecraft:falling_block"); + DataConverterEntity.a.put("Fireball", "minecraft:fireball"); + DataConverterEntity.a.put("FireworksRocketEntity", "minecraft:fireworks_rocket"); + DataConverterEntity.a.put("Ghast", "minecraft:ghast"); + DataConverterEntity.a.put("Giant", "minecraft:giant"); + DataConverterEntity.a.put("Guardian", "minecraft:guardian"); + DataConverterEntity.a.put("Horse", "minecraft:horse"); + DataConverterEntity.a.put("Husk", "minecraft:husk"); + DataConverterEntity.a.put("Item", "minecraft:item"); + DataConverterEntity.a.put("ItemFrame", "minecraft:item_frame"); + DataConverterEntity.a.put("LavaSlime", "minecraft:magma_cube"); + DataConverterEntity.a.put("LeashKnot", "minecraft:leash_knot"); + DataConverterEntity.a.put("MinecartChest", "minecraft:chest_minecart"); + DataConverterEntity.a.put("MinecartCommandBlock", "minecraft:commandblock_minecart"); + DataConverterEntity.a.put("MinecartFurnace", "minecraft:furnace_minecart"); + DataConverterEntity.a.put("MinecartHopper", "minecraft:hopper_minecart"); + DataConverterEntity.a.put("MinecartRideable", "minecraft:minecart"); + DataConverterEntity.a.put("MinecartSpawner", "minecraft:spawner_minecart"); + DataConverterEntity.a.put("MinecartTNT", "minecraft:tnt_minecart"); + DataConverterEntity.a.put("Mule", "minecraft:mule"); + DataConverterEntity.a.put("MushroomCow", "minecraft:mooshroom"); + DataConverterEntity.a.put("Ozelot", "minecraft:ocelot"); + DataConverterEntity.a.put("Painting", "minecraft:painting"); + DataConverterEntity.a.put("Pig", "minecraft:pig"); + DataConverterEntity.a.put("PigZombie", "minecraft:zombie_pigman"); + DataConverterEntity.a.put("PolarBear", "minecraft:polar_bear"); + DataConverterEntity.a.put("PrimedTnt", "minecraft:tnt"); + DataConverterEntity.a.put("Rabbit", "minecraft:rabbit"); + DataConverterEntity.a.put("Sheep", "minecraft:sheep"); + DataConverterEntity.a.put("Shulker", "minecraft:shulker"); + DataConverterEntity.a.put("ShulkerBullet", "minecraft:shulker_bullet"); + DataConverterEntity.a.put("Silverfish", "minecraft:silverfish"); + DataConverterEntity.a.put("Skeleton", "minecraft:skeleton"); + DataConverterEntity.a.put("SkeletonHorse", "minecraft:skeleton_horse"); + DataConverterEntity.a.put("Slime", "minecraft:slime"); + DataConverterEntity.a.put("SmallFireball", "minecraft:small_fireball"); + DataConverterEntity.a.put("SnowMan", "minecraft:snowman"); + DataConverterEntity.a.put("Snowball", "minecraft:snowball"); + DataConverterEntity.a.put("SpectralArrow", "minecraft:spectral_arrow"); + DataConverterEntity.a.put("Spider", "minecraft:spider"); + DataConverterEntity.a.put("Squid", "minecraft:squid"); + DataConverterEntity.a.put("Stray", "minecraft:stray"); + DataConverterEntity.a.put("ThrownEgg", "minecraft:egg"); + DataConverterEntity.a.put("ThrownEnderpearl", "minecraft:ender_pearl"); + DataConverterEntity.a.put("ThrownExpBottle", "minecraft:xp_bottle"); + DataConverterEntity.a.put("ThrownPotion", "minecraft:potion"); + DataConverterEntity.a.put("Villager", "minecraft:villager"); + DataConverterEntity.a.put("VillagerGolem", "minecraft:villager_golem"); + DataConverterEntity.a.put("Witch", "minecraft:witch"); + DataConverterEntity.a.put("WitherBoss", "minecraft:wither"); + DataConverterEntity.a.put("WitherSkeleton", "minecraft:wither_skeleton"); + DataConverterEntity.a.put("WitherSkull", "minecraft:wither_skull"); + DataConverterEntity.a.put("Wolf", "minecraft:wolf"); + DataConverterEntity.a.put("XPOrb", "minecraft:xp_orb"); + DataConverterEntity.a.put("Zombie", "minecraft:zombie"); + DataConverterEntity.a.put("ZombieHorse", "minecraft:zombie_horse"); + DataConverterEntity.a.put("ZombieVillager", "minecraft:zombie_villager"); + } + } + + private static class DataConverterPotionWater implements DataConverter { + + DataConverterPotionWater() {} + + public int getDataVersion() { + return 806; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + String s = cmp.getString("id"); + + if ("minecraft:potion".equals(s) || "minecraft:splash_potion".equals(s) || "minecraft:lingering_potion".equals(s) || "minecraft:tipped_arrow".equals(s)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (!nbttagcompound1.containsKey("Potion", 8)) { + nbttagcompound1.putString("Potion", "minecraft:water"); + } + + if (!cmp.containsKey("tag", 10)) { + cmp.put("tag", nbttagcompound1); + } + } + + return cmp; + } + } + + private static class DataConverterShulker implements DataConverter { + + DataConverterShulker() {} + + public int getDataVersion() { + return 808; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker".equals(cmp.getString("id")) && !cmp.containsKey("Color", 99)) { + cmp.putByte("Color", (byte) 10); + } + + return cmp; + } + } + + private static class DataConverterShulkerBoxItem implements DataConverter { + + public static final String[] a = new String[] { "minecraft:white_shulker_box", "minecraft:orange_shulker_box", "minecraft:magenta_shulker_box", "minecraft:light_blue_shulker_box", "minecraft:yellow_shulker_box", "minecraft:lime_shulker_box", "minecraft:pink_shulker_box", "minecraft:gray_shulker_box", "minecraft:silver_shulker_box", "minecraft:cyan_shulker_box", "minecraft:purple_shulker_box", "minecraft:blue_shulker_box", "minecraft:brown_shulker_box", "minecraft:green_shulker_box", "minecraft:red_shulker_box", "minecraft:black_shulker_box"}; + + DataConverterShulkerBoxItem() {} + + public int getDataVersion() { + return 813; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker_box".equals(cmp.getString("id")) && cmp.containsKey("tag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("tag"); + + if (nbttagcompound1.containsKey("BlockEntityTag", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttagcompound1.getCompound("BlockEntityTag"); + + if (nbttagcompound2.getList("Items", 10).isEmpty()) { + nbttagcompound2.remove("Items"); + } + + int i = nbttagcompound2.getInt("Color"); + + nbttagcompound2.remove("Color"); + if (nbttagcompound2.isEmpty()) { + nbttagcompound1.remove("BlockEntityTag"); + } + + if (nbttagcompound1.isEmpty()) { + cmp.remove("tag"); + } + + cmp.putString("id", DataConverterShulkerBoxItem.a[i % 16]); + } + } + + return cmp; + } + } + + private static class DataConverterShulkerBoxBlock implements DataConverter { + + DataConverterShulkerBoxBlock() {} + + public int getDataVersion() { + return 813; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:shulker".equals(cmp.getString("id"))) { + cmp.remove("Color"); + } + + return cmp; + } + } + + private static class DataConverterLang implements DataConverter { + + DataConverterLang() {} + + public int getDataVersion() { + return 816; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if (cmp.containsKey("lang", 8)) { + cmp.putString("lang", cmp.getString("lang").toLowerCase(Locale.ROOT)); + } + + return cmp; + } + } + + private static class DataConverterTotem implements DataConverter { + + DataConverterTotem() {} + + public int getDataVersion() { + return 820; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:totem".equals(cmp.getString("id"))) { + cmp.putString("id", "minecraft:totem_of_undying"); + } + + return cmp; + } + } + + private static class DataConverterBedBlock implements DataConverter { + + private static final Logger a = LogManager.getLogger(FabricDataFixer.class); + + DataConverterBedBlock() {} + + public int getDataVersion() { + return 1125; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + boolean flag = true; + + try { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + int i = nbttagcompound1.getInt("xPos"); + int j = nbttagcompound1.getInt("zPos"); + ListTag nbttaglist = nbttagcompound1.getList("TileEntities", 10); + ListTag nbttaglist1 = nbttagcompound1.getList("Sections", 10); + + for (int k = 0; k < nbttaglist1.size(); ++k) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist1.getCompoundTag(k); + byte b0 = nbttagcompound2.getByte("Y"); + byte[] abyte = nbttagcompound2.getByteArray("Blocks"); + + for (int l = 0; l < abyte.length; ++l) { + if (416 == (abyte[l] & 255) << 4) { + int i1 = l & 15; + int j1 = l >> 8 & 15; + int k1 = l >> 4 & 15; + net.minecraft.nbt.CompoundTag nbttagcompound3 = new net.minecraft.nbt.CompoundTag(); + + nbttagcompound3.putString("id", "bed"); + nbttagcompound3.putInt("x", i1 + (i << 4)); + nbttagcompound3.putInt("y", j1 + (b0 << 4)); + nbttagcompound3.putInt("z", k1 + (j << 4)); + nbttaglist.add(nbttagcompound3); + } + } + } + } catch (Exception exception) { + DataConverterBedBlock.a.warn("Unable to datafix Bed blocks, level format may be missing tags."); + } + + return cmp; + } + } + + private static class DataConverterBedItem implements DataConverter { + + DataConverterBedItem() {} + + public int getDataVersion() { + return 1125; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("minecraft:bed".equals(cmp.getString("id")) && cmp.getShort("Damage") == 0) { + cmp.putShort("Damage", (short) DyeColor.RED.getId()); + } + + return cmp; + } + } + + private static class DataConverterSignText implements DataConverter { + + public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { + Component a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + if (jsonelement.isJsonPrimitive()) { + return new TextComponent(jsonelement.getAsString()); + } else if (jsonelement.isJsonArray()) { + JsonArray jsonarray = jsonelement.getAsJsonArray(); + Component iTextComponent = null; + Iterator iterator = jsonarray.iterator(); + + while (iterator.hasNext()) { + JsonElement jsonelement1 = (JsonElement) iterator.next(); + Component iTextComponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); + + if (iTextComponent == null) { + iTextComponent = iTextComponent1; + } else { + iTextComponent.append(iTextComponent1); + } + } + + return iTextComponent; + } else { + throw new JsonParseException("Don\'t know how to turn " + jsonelement + " into a Component"); + } + } + + public Object deserialize(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + return this.a(jsonelement, type, jsondeserializationcontext); + } + }).create(); + + DataConverterSignText() {} + + public int getDataVersion() { + return 101; + } + + public net.minecraft.nbt.CompoundTag convert(net.minecraft.nbt.CompoundTag cmp) { + if ("Sign".equals(cmp.getString("id"))) { + this.convert(cmp, "Text1"); + this.convert(cmp, "Text2"); + this.convert(cmp, "Text3"); + this.convert(cmp, "Text4"); + } + + return cmp; + } + + private void convert(net.minecraft.nbt.CompoundTag nbttagcompound, String s) { + String s1 = nbttagcompound.getString(s); + Object object = null; + + if (!"null".equals(s1) && !Strings.isNullOrEmpty(s1)) { + if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { + object = new TextComponent(s1); + } else { + try { + object = JsonHelper.deserialize(DataConverterSignText.a, s1, Component.class, true); + if (object == null) { + object = new TextComponent(""); + } + } catch (JsonParseException jsonparseexception) { + ; + } + + if (object == null) { + try { + object = Component.Serializer.fromJsonString(s1); + } catch (JsonParseException jsonparseexception1) { + ; + } + } + + if (object == null) { + try { + object = Component.Serializer.fromLenientJsonString(s1); + } catch (JsonParseException jsonparseexception2) { + ; + } + } + + if (object == null) { + object = new TextComponent(s1); + } + } + } else { + object = new TextComponent(""); + } + + nbttagcompound.putString(s, Component.Serializer.toJsonString((Component) object)); + } + } + + private static class DataInspectorPlayerVehicle implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.containsKey("RootVehicle", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("RootVehicle"); + + if (nbttagcompound1.containsKey("Entity", 10)) { + convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); + } + } + + return cmp; + } + } + + private static class DataInspectorLevelPlayer implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.containsKey("Player", 10)) { + convertCompound(LegacyType.PLAYER, cmp, "Player", sourceVer, targetVer); + } + + return cmp; + } + } + + private static class DataInspectorStructure implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + ListTag nbttaglist; + int j; + net.minecraft.nbt.CompoundTag nbttagcompound1; + + if (cmp.containsKey("entities", 9)) { + nbttaglist = cmp.getList("entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (net.minecraft.nbt.CompoundTag) nbttaglist.get(j); + if (nbttagcompound1.containsKey("nbt", 10)) { + convertCompound(LegacyType.ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); + } + } + } + + if (cmp.containsKey("blocks", 9)) { + nbttaglist = cmp.getList("blocks", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttagcompound1 = (net.minecraft.nbt.CompoundTag) nbttaglist.get(j); + if (nbttagcompound1.containsKey("nbt", 10)) { + convertCompound(LegacyType.BLOCK_ENTITY, nbttagcompound1, "nbt", sourceVer, targetVer); + } + } + } + + return cmp; + } + } + + private static class DataInspectorChunks implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.containsKey("Level", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Level"); + ListTag nbttaglist; + int j; + + if (nbttagcompound1.containsKey("Entities", 9)) { + nbttaglist = nbttagcompound1.getList("Entities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); + } + } + + if (nbttagcompound1.containsKey("TileEntities", 9)) { + nbttaglist = nbttagcompound1.getList("TileEntities", 10); + + for (j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.BLOCK_ENTITY, (net.minecraft.nbt.CompoundTag) nbttaglist.get(j), sourceVer, targetVer)); + } + } + } + + return cmp; + } + } + + private static class DataInspectorEntityPassengers implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (cmp.containsKey("Passengers", 9)) { + ListTag nbttaglist = cmp.getList("Passengers", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + nbttaglist.set(j, convert(LegacyType.ENTITY, nbttaglist.getCompoundTag(j), sourceVer, targetVer)); + } + } + + return cmp; + } + } + + private static class DataInspectorPlayer implements DataInspector { + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + convertItems(cmp, "Inventory", sourceVer, targetVer); + convertItems(cmp, "EnderItems", sourceVer, targetVer); + if (cmp.containsKey("ShoulderEntityLeft", 10)) { + convertCompound(LegacyType.ENTITY, cmp, "ShoulderEntityLeft", sourceVer, targetVer); + } + + if (cmp.containsKey("ShoulderEntityRight", 10)) { + convertCompound(LegacyType.ENTITY, cmp, "ShoulderEntityRight", sourceVer, targetVer); + } + + return cmp; + } + } + + private static class DataInspectorVillagers implements DataInspector { + Identifier entityVillager = getKey("EntityVillager"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (entityVillager.equals(new Identifier(cmp.getString("id"))) && cmp.containsKey("Offers", 10)) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = cmp.getCompound("Offers"); + + if (nbttagcompound1.containsKey("Recipes", 9)) { + ListTag nbttaglist = nbttagcompound1.getList("Recipes", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + net.minecraft.nbt.CompoundTag nbttagcompound2 = nbttaglist.getCompoundTag(j); + + convertItem(nbttagcompound2, "buy", sourceVer, targetVer); + convertItem(nbttagcompound2, "buyB", sourceVer, targetVer); + convertItem(nbttagcompound2, "sell", sourceVer, targetVer); + nbttaglist.set(j, nbttagcompound2); + } + } + } + + return cmp; + } + } + + private static class DataInspectorMobSpawnerMinecart implements DataInspector { + Identifier entityMinecartMobSpawner = getKey("EntityMinecartMobSpawner"); + Identifier tileEntityMobSpawner = getKey("TileEntityMobSpawner"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + String s = cmp.getString("id"); + if (entityMinecartMobSpawner.equals(new Identifier(s))) { + cmp.putString("id", tileEntityMobSpawner.toString()); + convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); + cmp.putString("id", s); + } + + return cmp; + } + } + + private static class DataInspectorMobSpawnerMobs implements DataInspector { + Identifier tileEntityMobSpawner = getKey("TileEntityMobSpawner"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityMobSpawner.equals(new Identifier(cmp.getString("id")))) { + if (cmp.containsKey("SpawnPotentials", 9)) { + ListTag nbttaglist = cmp.getList("SpawnPotentials", 10); + + for (int j = 0; j < nbttaglist.size(); ++j) { + net.minecraft.nbt.CompoundTag nbttagcompound1 = nbttaglist.getCompoundTag(j); + + convertCompound(LegacyType.ENTITY, nbttagcompound1, "Entity", sourceVer, targetVer); + } + } + + convertCompound(LegacyType.ENTITY, cmp, "SpawnData", sourceVer, targetVer); + } + + return cmp; + } + } + + private static class DataInspectorCommandBlock implements DataInspector { + Identifier tileEntityCommand = getKey("TileEntityCommand"); + + @Override + public net.minecraft.nbt.CompoundTag inspect(net.minecraft.nbt.CompoundTag cmp, int sourceVer, int targetVer) { + if (tileEntityCommand.equals(new Identifier(cmp.getString("id")))) { + cmp.putString("id", "Control"); + convert(LegacyType.BLOCK_ENTITY, cmp, sourceVer, targetVer); + cmp.putString("id", "MinecartCommandBlock"); + } + + return cmp; + } + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricEntity.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricEntity.java new file mode 100644 index 000000000..d1fb75a04 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricEntity.java @@ -0,0 +1,116 @@ +/* + * 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.fabric; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.entity.metadata.EntityProperties; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.NullWorld; +import com.sk89q.worldedit.world.entity.EntityTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import java.lang.ref.WeakReference; + +import javax.annotation.Nullable; + +class FabricEntity implements Entity { + + private final WeakReference entityRef; + + FabricEntity(net.minecraft.entity.Entity entity) { + checkNotNull(entity); + this.entityRef = new WeakReference<>(entity); + } + + @Override + public BaseEntity getState() { + net.minecraft.entity.Entity entity = entityRef.get(); + if (entity != null) { + Identifier id = Registry.ENTITY_TYPE.getId(entity.getType()); + CompoundTag tag = new CompoundTag(); + entity.toTag(tag); + return new BaseEntity(EntityTypes.get(id.toString()), NBTConverter.fromNative(tag)); + } else { + return null; + } + } + + @Override + public Location getLocation() { + net.minecraft.entity.Entity entity = entityRef.get(); + if (entity != null) { + Vector3 position = Vector3.at(entity.x, entity.y, entity.z); + float yaw = entity.yaw; + float pitch = entity.pitch; + + return new Location(FabricAdapter.adapt(entity.world), position, yaw, pitch); + } else { + return new Location(NullWorld.getInstance()); + } + } + + @Override + public boolean setLocation(Location location) { + // TODO unused atm + return false; + } + + @Override + public Extent getExtent() { + net.minecraft.entity.Entity entity = entityRef.get(); + if (entity != null) { + return FabricAdapter.adapt(entity.world); + } else { + return NullWorld.getInstance(); + } + } + + @Override + public boolean remove() { + net.minecraft.entity.Entity entity = entityRef.get(); + if (entity != null) { + entity.remove(); + } + return true; + } + + @SuppressWarnings("unchecked") + @Nullable + @Override + public T getFacet(Class cls) { + net.minecraft.entity.Entity entity = entityRef.get(); + if (entity != null) { + if (EntityProperties.class.isAssignableFrom(cls)) { + return (T) new FabricEntityProperties(entity); + } else { + return null; + } + } else { + return null; + } + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricEntityProperties.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricEntityProperties.java new file mode 100644 index 000000000..eafbe5c94 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricEntityProperties.java @@ -0,0 +1,151 @@ +/* + * 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.fabric; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.sk89q.worldedit.entity.metadata.EntityProperties; +import net.minecraft.entity.EnderEyeEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.ExperienceOrbEntity; +import net.minecraft.entity.FallingBlockEntity; +import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.Npc; +import net.minecraft.entity.TntEntity; +import net.minecraft.entity.boss.dragon.EnderDragonEntity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.entity.decoration.ItemFrameEntity; +import net.minecraft.entity.decoration.painting.PaintingEntity; +import net.minecraft.entity.mob.AmbientEntity; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.passive.AnimalEntity; +import net.minecraft.entity.passive.TameableEntity; +import net.minecraft.entity.passive.GolemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.Projectile; +import net.minecraft.entity.vehicle.AbstractMinecartEntity; +import net.minecraft.entity.vehicle.BoatEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.village.Trader; + +public class FabricEntityProperties implements EntityProperties { + + private final Entity entity; + + public FabricEntityProperties(Entity entity) { + checkNotNull(entity); + this.entity = entity; + } + + @Override + public boolean isPlayerDerived() { + return entity instanceof PlayerEntity; + } + + @Override + public boolean isProjectile() { + return entity instanceof EnderEyeEntity || entity instanceof Projectile; + } + + @Override + public boolean isItem() { + return entity instanceof ItemEntity; + } + + @Override + public boolean isFallingBlock() { + return entity instanceof FallingBlockEntity; + } + + @Override + public boolean isPainting() { + return entity instanceof PaintingEntity; + } + + @Override + public boolean isItemFrame() { + return entity instanceof ItemFrameEntity; + } + + @Override + public boolean isBoat() { + return entity instanceof BoatEntity; + } + + @Override + public boolean isMinecart() { + return entity instanceof AbstractMinecartEntity; + } + + @Override + public boolean isTNT() { + return entity instanceof TntEntity; + } + + @Override + public boolean isExperienceOrb() { + return entity instanceof ExperienceOrbEntity; + } + + @Override + public boolean isLiving() { + return entity instanceof MobEntity; + } + + @Override + public boolean isAnimal() { + return entity instanceof AnimalEntity; + } + + @Override + public boolean isAmbient() { + return entity instanceof AmbientEntity; + } + + @Override + public boolean isNPC() { + return entity instanceof Npc || entity instanceof Trader; + } + + @Override + public boolean isGolem() { + return entity instanceof GolemEntity; + } + + @Override + public boolean isTamed() { + return entity instanceof TameableEntity && ((TameableEntity) entity).isTamed(); + } + + @Override + public boolean isTagged() { + return entity.hasCustomName(); + } + + @Override + public boolean isArmorStand() { + return entity instanceof ArmorStandEntity; + } + + @Override + public boolean isPasteable() { + return !(entity instanceof ServerPlayerEntity || entity instanceof EnderDragonEntity); + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemCategoryRegistry.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemCategoryRegistry.java new file mode 100644 index 000000000..e8ec3e43f --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemCategoryRegistry.java @@ -0,0 +1,46 @@ +/* + * 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.fabric; + +import com.sk89q.worldedit.registry.Category; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; +import net.minecraft.tag.ItemTags; +import net.minecraft.tag.Tag; +import net.minecraft.util.Identifier; + +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +public class FabricItemCategoryRegistry implements ItemCategoryRegistry { + @Override + public Set getCategorisedByName(String category) { + return Optional.ofNullable(ItemTags.getContainer().get(new Identifier(category))) + .map(Tag::values).orElse(Collections.emptySet()) + .stream().map(FabricAdapter::adapt).collect(Collectors.toSet()); + } + + @Override + public Set getAll(Category category) { + return getCategorisedByName(category.getId()); + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemRegistry.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemRegistry.java new file mode 100644 index 000000000..e3497234f --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemRegistry.java @@ -0,0 +1,42 @@ +/* + * 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.fabric; + +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.BundledItemRegistry; +import net.fabricmc.api.EnvType; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.item.Item; + +import javax.annotation.Nullable; + +public class FabricItemRegistry extends BundledItemRegistry { + + @Nullable + @Override + public String getName(ItemType itemType) { + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { + final Item item = FabricAdapter.adapt(itemType); + return I18n.translate(item.getTranslationKey()); + } + return super.getName(itemType); + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPermissionsProvider.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPermissionsProvider.java new file mode 100644 index 000000000..68ff54bef --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPermissionsProvider.java @@ -0,0 +1,50 @@ +/* + * 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.fabric; + +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.world.GameMode; + +public interface FabricPermissionsProvider { + + boolean hasPermission(ServerPlayerEntity player, String permission); + + void registerPermission(String permission); + + class VanillaPermissionsProvider implements FabricPermissionsProvider { + + private FabricPlatform platform; + + public VanillaPermissionsProvider(FabricPlatform platform) { + this.platform = platform; + } + + @Override + public boolean hasPermission(ServerPlayerEntity player, String permission) { + FabricConfiguration configuration = platform.getConfiguration(); + return configuration.cheatMode || + player.server.getPlayerManager().isOperator(player.getGameProfile()) || + (configuration.creativeEnable && player.interactionManager.getGameMode() == GameMode.CREATIVE); + } + + @Override + public void registerPermission(String permission) {} + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java new file mode 100644 index 000000000..69ea094b2 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java @@ -0,0 +1,202 @@ +/* + * 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.fabric; + +import com.sk89q.worldedit.command.util.PermissionCondition; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.AbstractPlatform; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.MultiUserPlatform; +import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.registry.Registries; +import net.minecraft.SharedConstants; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import org.enginehub.piston.Command; +import org.enginehub.piston.CommandManager; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static java.util.stream.Collectors.toList; + +class FabricPlatform extends AbstractPlatform implements MultiUserPlatform { + + private final FabricWorldEdit mod; + private final MinecraftServer server; + private final FabricDataFixer dataFixer; + private boolean hookingEvents = false; + + FabricPlatform(FabricWorldEdit mod, MinecraftServer server) { + this.mod = mod; + this.server = server; + this.dataFixer = new FabricDataFixer(getDataVersion()); + } + + boolean isHookingEvents() { + return hookingEvents; + } + + @Override + public Registries getRegistries() { + return FabricRegistries.getInstance(); + } + + @Override + public int getDataVersion() { + return SharedConstants.getGameVersion().getWorldVersion(); + } + + @Override + public DataFixer getDataFixer() { + return dataFixer; + } + + @Override + public boolean isValidMobType(String type) { + return Registry.ENTITY_TYPE.containsId(new Identifier(type)); + } + + @Override + public void reload() { + getConfiguration().load(); + } + + @Override + public int schedule(long delay, long period, Runnable task) { + return -1; + } + + @Override + public List getWorlds() { + Iterable worlds = server.getWorlds(); + List ret = new ArrayList<>(); + for (ServerWorld world : worlds) { + ret.add(new FabricWorld(world)); + } + return ret; + } + + @Nullable + @Override + public Player matchPlayer(Player player) { + if (player instanceof FabricPlayer) { + return player; + } else { + ServerPlayerEntity entity = server.getPlayerManager().getPlayer(player.getName()); + return entity != null ? new FabricPlayer(entity) : null; + } + } + + @Nullable + @Override + public World matchWorld(World world) { + if (world instanceof FabricWorld) { + return world; + } else { + for (ServerWorld ws : server.getWorlds()) { + if (ws.getLevelProperties().getLevelName().equals(world.getName())) { + return new FabricWorld(ws); + } + } + + return null; + } + } + + @Override + public void registerCommands(CommandManager manager) { + if (server == null) return; + net.minecraft.server.command.CommandManager mcMan = server.getCommandManager(); + + for (Command command : manager.getAllCommands().collect(toList())) { + CommandWrapper.register(mcMan.getDispatcher(), command); + Set perms = command.getCondition().as(PermissionCondition.class) + .map(PermissionCondition::getPermissions) + .orElseGet(Collections::emptySet); + if (!perms.isEmpty()) { + perms.forEach(FabricWorldEdit.inst.getPermissionsProvider()::registerPermission); + } + } + } + + @Override + public void registerGameHooks() { + // We registered the events already anyway, so we just 'turn them on' + hookingEvents = true; + } + + @Override + public FabricConfiguration getConfiguration() { + return mod.getConfig(); + } + + @Override + public String getVersion() { + return mod.getInternalVersion(); + } + + @Override + public String getPlatformName() { + return "Fabric-Official"; + } + + @Override + public String getPlatformVersion() { + return mod.getInternalVersion(); + } + + @Override + public Map getCapabilities() { + Map capabilities = new EnumMap<>(Capability.class); + capabilities.put(Capability.CONFIGURATION, Preference.PREFER_OTHERS); + capabilities.put(Capability.WORLDEDIT_CUI, Preference.NORMAL); + capabilities.put(Capability.GAME_HOOKS, Preference.NORMAL); + capabilities.put(Capability.PERMISSIONS, Preference.NORMAL); + capabilities.put(Capability.USER_COMMANDS, Preference.NORMAL); + capabilities.put(Capability.WORLD_EDITING, Preference.PREFERRED); + return capabilities; + } + + @Override + public Collection getConnectedUsers() { + List users = new ArrayList<>(); + PlayerManager scm = server.getPlayerManager(); + for (ServerPlayerEntity entity : scm.getPlayerList()) { + if (entity != null) { + users.add(new FabricPlayer(entity)); + } + } + return users; + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java new file mode 100644 index 000000000..1944b3063 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java @@ -0,0 +1,267 @@ +/* + * 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.fabric; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.util.StringUtil; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.extension.platform.AbstractPlayerActor; +import com.sk89q.worldedit.extent.inventory.BlockBag; +import com.sk89q.worldedit.fabric.net.handler.WECUIPacketHandler; +import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.session.SessionKey; +import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.block.BlockTypes; +import io.netty.buffer.Unpooled; +import net.minecraft.ChatFormat; +import net.minecraft.block.Block; +import net.minecraft.client.network.packet.BlockEntityUpdateS2CPacket; +import net.minecraft.client.network.packet.BlockUpdateS2CPacket; +import net.minecraft.client.network.packet.CustomPayloadS2CPacket; +import net.minecraft.item.ItemStack; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Hand; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; +import net.minecraft.util.math.BlockPos; + +import java.io.IOException; +import java.util.UUID; + +import javax.annotation.Nullable; + +public class FabricPlayer extends AbstractPlayerActor { + + // see ClientPlayNetHandler: search for "invalid update packet", lots of hardcoded consts + private static final int STRUCTURE_BLOCK_PACKET_ID = 7; + private final ServerPlayerEntity player; + + protected FabricPlayer(ServerPlayerEntity player) { + this.player = player; + ThreadSafeCache.getInstance().getOnlineIds().add(getUniqueId()); + } + + @Override + public UUID getUniqueId() { + return player.getUuid(); + } + + @Override + public BaseItemStack getItemInHand(HandSide handSide) { + ItemStack is = this.player.getStackInHand(handSide == HandSide.MAIN_HAND ? Hand.MAIN_HAND : Hand.OFF_HAND); + return FabricAdapter.adapt(is); + } + + @Override + public String getName() { + return this.player.getName().getFormattedText(); + } + + @Override + public BaseEntity getState() { + throw new UnsupportedOperationException("Cannot create a state from this object"); + } + + @Override + public Location getLocation() { + Vector3 position = Vector3.at(this.player.x, this.player.y, this.player.z); + return new Location( + FabricWorldEdit.inst.getWorld(this.player.world), + position, + this.player.yaw, + this.player.pitch); + } + + @Override + public boolean setLocation(Location location) { + // TODO + return false; + } + + @Override + public com.sk89q.worldedit.world.World getWorld() { + return FabricWorldEdit.inst.getWorld(this.player.world); + } + + @Override + public void giveItem(BaseItemStack itemStack) { + this.player.inventory.insertStack(FabricAdapter.adapt(itemStack)); + } + + @Override + public void dispatchCUIEvent(CUIEvent event) { + String[] params = event.getParameters(); + String send = event.getTypeId(); + if (params.length > 0) { + send = send + "|" + StringUtil.joinString(params, "|"); + } + PacketByteBuf buffer = new PacketByteBuf(Unpooled.copiedBuffer(send.getBytes(WECUIPacketHandler.UTF_8_CHARSET))); + CustomPayloadS2CPacket packet = new CustomPayloadS2CPacket(new Identifier(FabricWorldEdit.MOD_ID, FabricWorldEdit.CUI_PLUGIN_CHANNEL), buffer); + this.player.networkHandler.sendPacket(packet); + } + + @Override + public void printRaw(String msg) { + for (String part : msg.split("\n")) { + this.player.sendMessage(new TextComponent(part)); + } + } + + @Override + public void printDebug(String msg) { + sendColorized(msg, ChatFormat.GRAY); + } + + @Override + public void print(String msg) { + sendColorized(msg, ChatFormat.LIGHT_PURPLE); + } + + @Override + public void printError(String msg) { + sendColorized(msg, ChatFormat.RED); + } + + @Override + public void print(Component component) { + this.player.sendMessage(net.minecraft.network.chat.Component.Serializer.fromJsonString(GsonComponentSerializer.INSTANCE.serialize(component))); + } + + private void sendColorized(String msg, ChatFormat formatting) { + for (String part : msg.split("\n")) { + TextComponent component = new TextComponent(part); + component.getStyle().setColor(formatting); + this.player.sendMessage(component); + } + } + + @Override + public void setPosition(Vector3 pos, float pitch, float yaw) { + this.player.networkHandler.requestTeleport(pos.getX(), pos.getY(), pos.getZ(), yaw, pitch); + } + + @Override + public String[] getGroups() { + return new String[]{}; // WorldEditMod.inst.getPermissionsResolver().getGroups(this.player.username); + } + + @Override + public BlockBag getInventoryBlockBag() { + return null; + } + + @Override + public boolean hasPermission(String perm) { + return FabricWorldEdit.inst.getPermissionsProvider().hasPermission(player, perm); + } + + @Nullable + @Override + public T getFacet(Class cls) { + return null; + } + + @Override + public > void sendFakeBlock(BlockVector3 pos, B block) { + World world = getWorld(); + if (!(world instanceof FabricWorld)) { + return; + } + BlockPos loc = FabricAdapter.toBlockPos(pos); + if (block == null) { + final BlockUpdateS2CPacket packetOut = new BlockUpdateS2CPacket(((FabricWorld) world).getWorld(), loc); + player.networkHandler.sendPacket(packetOut); + } else { + final BlockUpdateS2CPacket packetOut = new BlockUpdateS2CPacket(); + PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); + buf.writeBlockPos(loc); + buf.writeVarInt(Block.getRawIdFromState(FabricAdapter.adapt(block.toImmutableState()))); + try { + packetOut.read(buf); + } catch (IOException e) { + return; + } + player.networkHandler.sendPacket(packetOut); + if (block instanceof BaseBlock && block.getBlockType().equals(BlockTypes.STRUCTURE_BLOCK)) { + final BaseBlock baseBlock = (BaseBlock) block; + final CompoundTag nbtData = baseBlock.getNbtData(); + if (nbtData != null) { + player.networkHandler.sendPacket(new BlockEntityUpdateS2CPacket( + new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()), + STRUCTURE_BLOCK_PACKET_ID, + NBTConverter.toNative(nbtData)) + ); + } + } + } + } + + @Override + public SessionKey getSessionKey() { + return new SessionKeyImpl(player.getUuid(), player.getName().getString()); + } + + private static class SessionKeyImpl implements SessionKey { + // If not static, this will leak a reference + + private final UUID uuid; + private final String name; + + private SessionKeyImpl(UUID uuid, String name) { + this.uuid = uuid; + this.name = name; + } + + @Override + public UUID getUniqueId() { + return uuid; + } + + @Nullable + @Override + public String getName() { + return name; + } + + @Override + public boolean isActive() { + // We can't directly check if the player is online because + // the list of players is not thread safe + return ThreadSafeCache.getInstance().getOnlineIds().contains(uuid); + } + + @Override + public boolean isPersistent() { + return true; + } + + } + +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricRegistries.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricRegistries.java new file mode 100644 index 000000000..7c703b723 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricRegistries.java @@ -0,0 +1,75 @@ +/* + * 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.fabric; + +import com.sk89q.worldedit.world.registry.BiomeRegistry; +import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; +import com.sk89q.worldedit.world.registry.BlockRegistry; +import com.sk89q.worldedit.world.registry.BundledRegistries; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; +import com.sk89q.worldedit.world.registry.ItemRegistry; + +/** + * World data for the Fabric platform. + */ +class FabricRegistries extends BundledRegistries { + + private static final FabricRegistries INSTANCE = new FabricRegistries(); + private final BlockRegistry blockRegistry = new FabricBlockRegistry(); + private final BiomeRegistry biomeRegistry = new FabricBiomeRegistry(); + private final ItemRegistry itemRegistry = new FabricItemRegistry(); + private final BlockCategoryRegistry blockCategoryRegistry = new FabricBlockCategoryRegistry(); + private final ItemCategoryRegistry itemCategoryRegistry = new FabricItemCategoryRegistry(); + + @Override + public BlockRegistry getBlockRegistry() { + return blockRegistry; + } + + @Override + public BiomeRegistry getBiomeRegistry() { + return biomeRegistry; + } + + @Override + public ItemRegistry getItemRegistry() { + return itemRegistry; + } + + @Override + public BlockCategoryRegistry getBlockCategoryRegistry() { + return blockCategoryRegistry; + } + + @Override + public ItemCategoryRegistry getItemCategoryRegistry() { + return itemCategoryRegistry; + } + + /** + * Get a static instance. + * + * @return an instance + */ + public static FabricRegistries getInstance() { + return INSTANCE; + } + +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java new file mode 100644 index 000000000..8125fb0cb --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java @@ -0,0 +1,597 @@ +/* + * 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.fabric; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.io.Files; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItem; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.internal.Constants; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.TreeGenerator.TreeType; +import com.sk89q.worldedit.world.AbstractWorld; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.item.ItemTypes; +import com.sk89q.worldedit.world.weather.WeatherType; +import com.sk89q.worldedit.world.weather.WeatherTypes; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.block.LeavesBlock; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.ItemEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.WorldGenerationProgressListener; +import net.minecraft.server.world.ServerChunkManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Clearable; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldSaveHandler; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkManager; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.WorldChunk; +import net.minecraft.world.gen.feature.BirchTreeFeature; +import net.minecraft.world.gen.feature.DarkOakTreeFeature; +import net.minecraft.world.gen.feature.DefaultFeatureConfig; +import net.minecraft.world.gen.feature.Feature; +import net.minecraft.world.gen.feature.FeatureConfig; +import net.minecraft.world.gen.feature.HugeBrownMushroomFeature; +import net.minecraft.world.gen.feature.HugeRedMushroomFeature; +import net.minecraft.world.gen.feature.JungleGroundBushFeature; +import net.minecraft.world.gen.feature.JungleTreeFeature; +import net.minecraft.world.gen.feature.LargeOakTreeFeature; +import net.minecraft.world.gen.feature.MegaJungleTreeFeature; +import net.minecraft.world.gen.feature.MegaPineTreeFeature; +import net.minecraft.world.gen.feature.OakTreeFeature; +import net.minecraft.world.gen.feature.PineTreeFeature; +import net.minecraft.world.gen.feature.PlantedFeatureConfig; +import net.minecraft.world.gen.feature.SavannaTreeFeature; +import net.minecraft.world.gen.feature.SpruceTreeFeature; +import net.minecraft.world.gen.feature.SwampTreeFeature; +import net.minecraft.world.level.LevelProperties; + +import java.io.File; +import java.lang.ref.WeakReference; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.Random; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; + +/** + * An adapter to Minecraft worlds for WorldEdit. + */ +public class FabricWorld extends AbstractWorld { + + private static final Random random = new Random(); + private static final int UPDATE = 1, NOTIFY = 2; + + private static final net.minecraft.block.BlockState JUNGLE_LOG = Blocks.JUNGLE_LOG.getDefaultState(); + private static final net.minecraft.block.BlockState JUNGLE_LEAF = Blocks.JUNGLE_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE); + private static final net.minecraft.block.BlockState JUNGLE_SHRUB = Blocks.OAK_LEAVES.getDefaultState().with(LeavesBlock.PERSISTENT, Boolean.TRUE); + + private final WeakReference worldRef; + + /** + * Construct a new world. + * + * @param world the world + */ + FabricWorld(World world) { + checkNotNull(world); + this.worldRef = new WeakReference<>(world); + } + + /** + * Get the underlying handle to the world. + * + * @return the world + * @throws WorldEditException thrown if a reference to the world was lost (i.e. world was unloaded) + */ + public World getWorldChecked() throws WorldEditException { + World world = worldRef.get(); + if (world != null) { + return world; + } else { + throw new WorldReferenceLostException("The reference to the world was lost (i.e. the world may have been unloaded)"); + } + } + + /** + * Get the underlying handle to the world. + * + * @return the world + * @throws RuntimeException thrown if a reference to the world was lost (i.e. world was unloaded) + */ + public World getWorld() { + World world = worldRef.get(); + if (world != null) { + return world; + } else { + throw new RuntimeException("The reference to the world was lost (i.e. the world may have been unloaded)"); + } + } + + @Override + public String getName() { + return getWorld().getLevelProperties().getLevelName(); + } + + @Override + public Path getStoragePath() { + final World world = getWorld(); + if (world instanceof ServerWorld) { + return ((ServerWorld) world).getSaveHandler().getWorldDir().toPath(); + } + return null; + } + + @Override + public > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { + checkNotNull(position); + checkNotNull(block); + + World world = getWorldChecked(); + int x = position.getBlockX(); + int y = position.getBlockY(); + int z = position.getBlockZ(); + + // First set the block + Chunk chunk = world.getChunk(x >> 4, z >> 4); + BlockPos pos = new BlockPos(x, y, z); + net.minecraft.block.BlockState old = chunk.getBlockState(pos); + OptionalInt stateId = BlockStateIdAccess.getBlockStateId(block.toImmutableState()); + net.minecraft.block.BlockState newState = stateId.isPresent() ? Block.getStateFromRawId(stateId.getAsInt()) : FabricAdapter.adapt(block.toImmutableState()); + net.minecraft.block.BlockState successState = chunk.setBlockState(pos, newState, false); + boolean successful = successState != null; + + // Create the TileEntity + if (successful || old == newState) { + if (block instanceof BaseBlock) { + CompoundTag tag = ((BaseBlock) block).getNbtData(); + if (tag != null) { + net.minecraft.nbt.CompoundTag nativeTag = NBTConverter.toNative(tag); + nativeTag.putString("id", ((BaseBlock) block).getNbtId()); + TileEntityUtils.setTileEntity(world, position, nativeTag); + successful = true; // update if TE changed as well + } + } + } + + if (successful && notifyAndLight) { + world.getChunkManager().getLightingProvider().enqueueLightUpdate(pos); + world.updateListeners(pos, old, newState, UPDATE | NOTIFY); + } + + return successful; + } + + @Override + public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { + BlockPos pos = new BlockPos(position.getX(), position.getY(), position.getZ()); + getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), getWorld().getBlockState(pos), 1 | 2); + return true; + } + + @Override + public int getBlockLightLevel(BlockVector3 position) { + checkNotNull(position); + return getWorld().getLightLevel(FabricAdapter.toBlockPos(position)); + } + + @Override + public boolean clearContainerBlockContents(BlockVector3 position) { + checkNotNull(position); + BlockEntity tile = getWorld().getBlockEntity(FabricAdapter.toBlockPos(position)); + if ((tile instanceof Clearable)) { + ((Clearable) tile).clear(); + return true; + } + return false; + } + + @Override + public BiomeType getBiome(BlockVector2 position) { + checkNotNull(position); + return FabricAdapter.adapt(getWorld().getBiome(new BlockPos(position.getBlockX(), 0, position.getBlockZ()))); + } + + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + checkNotNull(position); + checkNotNull(biome); + + Chunk chunk = getWorld().getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4, ChunkStatus.FULL, false); + if (chunk == null) { + return false; + } + chunk.getBiomeArray()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = FabricAdapter.adapt(biome); + return true; + } + + private static final LoadingCache fakePlayers + = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(WorldEditFakePlayer::new)); + + @Override + public boolean useItem(BlockVector3 position, BaseItem item, Direction face) { + ItemStack stack = FabricAdapter.adapt(new BaseItemStack(item.getType(), item.getNbtData(), 1)); + ServerWorld world = (ServerWorld) getWorld(); + final WorldEditFakePlayer fakePlayer; + try { + fakePlayer = fakePlayers.get(world); + } catch (ExecutionException ignored) { + return false; + } + fakePlayer.setStackInHand(Hand.MAIN_HAND, stack); + fakePlayer.setPositionAndAngles(position.getBlockX(), position.getBlockY(), position.getBlockZ(), + (float) face.toVector().toYaw(), (float) face.toVector().toPitch()); + final BlockPos blockPos = FabricAdapter.toBlockPos(position); + final BlockHitResult rayTraceResult = new BlockHitResult(FabricAdapter.toVec3(position), + FabricAdapter.adapt(face), blockPos, false); + ItemUsageContext itemUseContext = new ItemUsageContext(fakePlayer, Hand.MAIN_HAND, rayTraceResult); + ActionResult used = stack.useOnBlock(itemUseContext); + if (used != ActionResult.SUCCESS) { + // try activating the block + if (getWorld().getBlockState(blockPos).activate(world, fakePlayer, Hand.MAIN_HAND, rayTraceResult)) { + used = ActionResult.SUCCESS; + } else { + used = stack.getItem().use(world, fakePlayer, Hand.MAIN_HAND).getResult(); + } + } + return used == ActionResult.SUCCESS; + } + + @Override + public void dropItem(Vector3 position, BaseItemStack item) { + checkNotNull(position); + checkNotNull(item); + + if (item.getType() == ItemTypes.AIR) { + return; + } + + ItemEntity entity = new ItemEntity(getWorld(), position.getX(), position.getY(), position.getZ(), FabricAdapter.adapt(item)); + entity.setPickupDelay(10); + getWorld().spawnEntity(entity); + } + + @Override + public void simulateBlockMine(BlockVector3 position) { + BlockPos pos = FabricAdapter.toBlockPos(position); + getWorld().breakBlock(pos, true); + } + + @Override + public boolean regenerate(Region region, EditSession editSession) { + // Don't even try to regen if it's going to fail. + ChunkManager provider = getWorld().getChunkManager(); + if (!(provider instanceof ServerChunkManager)) { + return false; + } + + File saveFolder = Files.createTempDir(); + // register this just in case something goes wrong + // normally it should be deleted at the end of this method + saveFolder.deleteOnExit(); + try { + ServerWorld originalWorld = (ServerWorld) getWorld(); + + MinecraftServer server = originalWorld.getServer(); + WorldSaveHandler saveHandler = new WorldSaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDir().getName(), server, server.getDataFixer()); + World freshWorld = new ServerWorld(server, server.getWorkerExecutor(), saveHandler, originalWorld.getLevelProperties(), + originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener()); + + // Pre-gen all the chunks + // We need to also pull one more chunk in every direction + CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16)); + for (BlockVector2 chunk : expandedPreGen.getChunks()) { + freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ()); + } + + FabricWorld from = new FabricWorld(freshWorld); + for (BlockVector3 vec : region) { + editSession.setBlock(vec, from.getFullBlock(vec)); + } + } catch (MaxChangedBlocksException e) { + throw new RuntimeException(e); + } finally { + saveFolder.delete(); + } + + return true; + } + + @Nullable + private static Feature createTreeFeatureGenerator(TreeType type) { + switch (type) { + case TREE: return new OakTreeFeature(DefaultFeatureConfig::deserialize, true); + case BIG_TREE: return new LargeOakTreeFeature(DefaultFeatureConfig::deserialize, true); + case REDWOOD: return new PineTreeFeature(DefaultFeatureConfig::deserialize); + case TALL_REDWOOD: return new SpruceTreeFeature(DefaultFeatureConfig::deserialize, true); + case BIRCH: return new BirchTreeFeature(DefaultFeatureConfig::deserialize, true, false); + case JUNGLE: return new MegaJungleTreeFeature(DefaultFeatureConfig::deserialize, true, 10, 20, JUNGLE_LOG, JUNGLE_LEAF); + case SMALL_JUNGLE: return new JungleTreeFeature(DefaultFeatureConfig::deserialize, true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, false); + case SHORT_JUNGLE: return new JungleTreeFeature(DefaultFeatureConfig::deserialize, true, 4 + random.nextInt(7), JUNGLE_LOG, JUNGLE_LEAF, true); + case JUNGLE_BUSH: return new JungleGroundBushFeature(DefaultFeatureConfig::deserialize, JUNGLE_LOG, JUNGLE_SHRUB); + case SWAMP: return new SwampTreeFeature(DefaultFeatureConfig::deserialize); + case ACACIA: return new SavannaTreeFeature(DefaultFeatureConfig::deserialize, true); + case DARK_OAK: return new DarkOakTreeFeature(DefaultFeatureConfig::deserialize, true); + case MEGA_REDWOOD: return new MegaPineTreeFeature(DefaultFeatureConfig::deserialize, true, random.nextBoolean()); + case TALL_BIRCH: return new BirchTreeFeature(DefaultFeatureConfig::deserialize, true, true); + case RED_MUSHROOM: return new HugeRedMushroomFeature(PlantedFeatureConfig::deserialize); + case BROWN_MUSHROOM: return new HugeBrownMushroomFeature(PlantedFeatureConfig::deserialize); + case RANDOM: return createTreeFeatureGenerator(TreeType.values()[ThreadLocalRandom.current().nextInt(TreeType.values().length)]); + default: + return null; + } + } + + private FeatureConfig createFeatureConfig(TreeType type) { + if (type == TreeType.RED_MUSHROOM || type == TreeType.BROWN_MUSHROOM) { + return new PlantedFeatureConfig(true); + } else { + return new DefaultFeatureConfig(); + } + } + + @Override + public boolean generateTree(TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException { + @SuppressWarnings("unchecked") + Feature generator = (Feature) createTreeFeatureGenerator(type); + return generator != null + && generator.generate(getWorld(), getWorld().getChunkManager().getChunkGenerator(), random, + FabricAdapter.toBlockPos(position), createFeatureConfig(type)); + } + + @Override + public void checkLoadedChunk(BlockVector3 pt) { + getWorld().getChunk(FabricAdapter.toBlockPos(pt)); + } + + @Override + public void fixAfterFastMode(Iterable chunks) { + fixLighting(chunks); + } + + @Override + public void fixLighting(Iterable chunks) { + World world = getWorld(); + for (BlockVector2 chunk : chunks) { + world.getChunkManager().getLightingProvider().suppressLight(new ChunkPos(chunk.getBlockX(), chunk.getBlockZ()), true); + } + } + + @Override + public boolean playEffect(Vector3 position, int type, int data) { + getWorld().playLevelEvent(type, FabricAdapter.toBlockPos(position.toBlockPoint()), data); + return true; + } + + @Override + public WeatherType getWeather() { + LevelProperties info = getWorld().getLevelProperties(); + if (info.isThundering()) { + return WeatherTypes.THUNDER_STORM; + } + if (info.isRaining()) { + return WeatherTypes.RAIN; + } + return WeatherTypes.CLEAR; + } + + @Override + public long getRemainingWeatherDuration() { + LevelProperties info = getWorld().getLevelProperties(); + if (info.isThundering()) { + return info.getThunderTime(); + } + if (info.isRaining()) { + return info.getRainTime(); + } + return info.getClearWeatherTime(); + } + + @Override + public void setWeather(WeatherType weatherType) { + setWeather(weatherType, 0); + } + + @Override + public void setWeather(WeatherType weatherType, long duration) { + LevelProperties info = getWorld().getLevelProperties(); + if (weatherType == WeatherTypes.THUNDER_STORM) { + info.setClearWeatherTime(0); + info.setThundering(true); + info.setThunderTime((int) duration); + } else if (weatherType == WeatherTypes.RAIN) { + info.setClearWeatherTime(0); + info.setRaining(true); + info.setRainTime((int) duration); + } else if (weatherType == WeatherTypes.CLEAR) { + info.setRaining(false); + info.setThundering(false); + info.setClearWeatherTime((int) duration); + } + } + + @Override + public int getMaxY() { + return getWorld().getHeight() - 1; + } + + @Override + public BlockVector3 getSpawnPosition() { + return FabricAdapter.adapt(getWorld().getSpawnPos()); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + net.minecraft.block.BlockState mcState = getWorld() + .getChunk(position.getBlockX() >> 4, position.getBlockZ() >> 4) + .getBlockState(FabricAdapter.toBlockPos(position)); + + BlockState matchingBlock = BlockStateIdAccess.getBlockStateById(Block.getRawIdFromState(mcState)); + if (matchingBlock != null) { + return matchingBlock; + } + + return FabricAdapter.adapt(mcState); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + BlockPos pos = new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()); + // Avoid creation by using the CHECK mode -- if it's needed, it'll be re-created anyways + BlockEntity tile = ((WorldChunk) getWorld().getChunk(pos)).getBlockEntity(pos, WorldChunk.CreationType.CHECK); + + if (tile != null) { + return getBlock(position).toBaseBlock(NBTConverter.fromNative(TileEntityUtils.copyNbtData(tile))); + } else { + return getBlock(position).toBaseBlock(); + } + } + + @Override + public int hashCode() { + return getWorld().hashCode(); + } + + @Override + public boolean equals(Object o) { + if ((o instanceof FabricWorld)) { + FabricWorld other = ((FabricWorld) o); + World otherWorld = other.worldRef.get(); + World thisWorld = worldRef.get(); + return otherWorld != null && otherWorld.equals(thisWorld); + } else if (o instanceof com.sk89q.worldedit.world.World) { + return ((com.sk89q.worldedit.world.World) o).getName().equals(getName()); + } else { + return false; + } + } + + @Override + public List getEntities(Region region) { + final World world = getWorld(); + if (!(world instanceof ServerWorld)) { + return Collections.emptyList(); + } + return ((ServerWorld) world).getEntities(null, entity -> true) + .stream() + .filter(e -> region.contains(FabricAdapter.adapt(e.getBlockPos()))) + .map(FabricEntity::new).collect(Collectors.toList()); + } + + @Override + public List getEntities() { + final World world = getWorld(); + if (!(world instanceof ServerWorld)) { + return Collections.emptyList(); + } + return ((ServerWorld) world).getEntities(null, entity -> true) + .stream() + .map(FabricEntity::new) + .collect(Collectors.toList()); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + World world = getWorld(); + final Optional> entityType = EntityType.get(entity.getType().getId()); + if (!entityType.isPresent()) return null; + net.minecraft.entity.Entity createdEntity = entityType.get().create(world); + if (createdEntity != null) { + CompoundTag nativeTag = entity.getNbtData(); + if (nativeTag != null) { + net.minecraft.nbt.CompoundTag tag = NBTConverter.toNative(entity.getNbtData()); + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + createdEntity.fromTag(tag); + } + + createdEntity.setPositionAndAngles(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + + world.spawnEntity(createdEntity); + return new FabricEntity(createdEntity); + } else { + return null; + } + } + + /** + * Thrown when the reference to the world is lost. + */ + @SuppressWarnings("serial") + private static final class WorldReferenceLostException extends WorldEditException { + private WorldReferenceLostException(String message) { + super(message); + } + } + + private static class NoOpChunkStatusListener implements WorldGenerationProgressListener { + @Override + public void start(ChunkPos chunkPos) { + } + + @Override + public void setChunkStatus(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) { + } + + @Override + public void stop() { + } + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorldEdit.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorldEdit.java new file mode 100644 index 000000000..0175a618a --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorldEdit.java @@ -0,0 +1,326 @@ +/* + * 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.fabric; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.sk89q.worldedit.fabric.FabricAdapter.adaptPlayer; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.event.platform.PlatformReadyEvent; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.fabric.net.handler.WECUIPacketHandler; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.item.ItemCategory; +import com.sk89q.worldedit.world.item.ItemType; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.player.AttackBlockCallback; +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.fabricmc.fabric.api.event.player.UseItemCallback; +import net.fabricmc.fabric.api.event.server.ServerStartCallback; +import net.fabricmc.fabric.api.event.server.ServerStopCallback; +import net.fabricmc.fabric.api.event.server.ServerTickCallback; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.tag.BlockTags; +import net.minecraft.tag.ItemTags; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.Identifier; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * The Fabric implementation of WorldEdit. + */ +public class FabricWorldEdit implements ModInitializer { + + private static final Logger LOGGER = LogManager.getLogger(); + public static final String MOD_ID = "worldedit"; + public static final String CUI_PLUGIN_CHANNEL = "cui"; + + private FabricPermissionsProvider provider; + + public static FabricWorldEdit inst; + + private FabricPlatform platform; + private FabricConfiguration config; + private Path workingDir; + + private ModContainer container; + + public FabricWorldEdit() { + inst = this; + } + + @Override + public void onInitialize() { + this.container = FabricLoader.getInstance().getModContainer("worldedit").orElseThrow( + () -> new IllegalStateException("WorldEdit mod missing in Fabric") + ); + + // Setup working directory + workingDir = new File(FabricLoader.getInstance().getConfigDirectory(), "worldedit").toPath(); + if (!Files.exists(workingDir)) { + try { + Files.createDirectory(workingDir); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + WECUIPacketHandler.init(); + + ServerTickCallback.EVENT.register(ThreadSafeCache.getInstance()); + ServerStartCallback.EVENT.register(this::onStartServer); + ServerStopCallback.EVENT.register(this::onStopServer); + AttackBlockCallback.EVENT.register(this::onLeftClickBlock); + UseBlockCallback.EVENT.register(this::onRightClickBlock); + UseItemCallback.EVENT.register(this::onRightClickAir); + LOGGER.info("WorldEdit for Fabric (version " + getInternalVersion() + ") is loaded"); + } + + private void setupPlatform(MinecraftServer server) { + this.platform = new FabricPlatform(this, server); + + WorldEdit.getInstance().getPlatformManager().register(platform); + + this.provider = new FabricPermissionsProvider.VanillaPermissionsProvider(platform); + } + + private void setupRegistries() { + // Blocks + for (Identifier name : Registry.BLOCK.getIds()) { + if (BlockType.REGISTRY.get(name.toString()) == null) { + BlockType.REGISTRY.register(name.toString(), new BlockType(name.toString(), + input -> FabricAdapter.adapt(FabricAdapter.adapt(input.getBlockType()).getDefaultState()))); + } + } + // Items + for (Identifier name : Registry.ITEM.getIds()) { + if (ItemType.REGISTRY.get(name.toString()) == null) { + ItemType.REGISTRY.register(name.toString(), new ItemType(name.toString())); + } + } + // Entities + for (Identifier name : Registry.ENTITY_TYPE.getIds()) { + if (EntityType.REGISTRY.get(name.toString()) == null) { + EntityType.REGISTRY.register(name.toString(), new EntityType(name.toString())); + } + } + // Biomes + for (Identifier name : Registry.BIOME.getIds()) { + if (BiomeType.REGISTRY.get(name.toString()) == null) { + BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); + } + } + // Tags + for (Identifier name : BlockTags.getContainer().getKeys()) { + if (BlockCategory.REGISTRY.get(name.toString()) == null) { + BlockCategory.REGISTRY.register(name.toString(), new BlockCategory(name.toString())); + } + } + for (Identifier name : ItemTags.getContainer().getKeys()) { + if (ItemCategory.REGISTRY.get(name.toString()) == null) { + ItemCategory.REGISTRY.register(name.toString(), new ItemCategory(name.toString())); + } + } + } + + private void onStartServer(MinecraftServer minecraftServer) { + setupPlatform(minecraftServer); + setupRegistries(); + + config = new FabricConfiguration(this); + config.load(); + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + } + + private void onStopServer(MinecraftServer minecraftServer) { + WorldEdit worldEdit = WorldEdit.getInstance(); + worldEdit.getSessionManager().unload(); + worldEdit.getPlatformManager().unregister(platform); + } + + private boolean shouldSkip() { + if (platform == null) { + return true; + } + + return !platform.isHookingEvents(); // We have to be told to catch these events + } + + private ActionResult onLeftClickBlock(PlayerEntity playerEntity, World world, Hand hand, BlockPos blockPos, Direction direction) { + if (shouldSkip() || hand == Hand.OFF_HAND || world.isClient) { + return ActionResult.PASS; + } + + WorldEdit we = WorldEdit.getInstance(); + FabricPlayer player = adaptPlayer((ServerPlayerEntity) playerEntity); + FabricWorld localWorld = getWorld(world); + Location pos = new Location(localWorld, + blockPos.getX(), + blockPos.getY(), + blockPos.getZ() + ); + + if (we.handleBlockLeftClick(player, pos)) { + return ActionResult.SUCCESS; + } + + if (we.handleArmSwing(player)) { + return ActionResult.SUCCESS; + } + + return ActionResult.PASS; + } + + public void onLeftClickAir(PlayerEntity playerEntity, World world, Hand hand) { + WorldEdit we = WorldEdit.getInstance(); + FabricPlayer player = adaptPlayer((ServerPlayerEntity) playerEntity); + we.handleArmSwing(player); + } + + private ActionResult onRightClickBlock(PlayerEntity playerEntity, World world, Hand hand, BlockHitResult blockHitResult) { + if (shouldSkip() || hand == Hand.OFF_HAND || world.isClient) { + return ActionResult.PASS; + } + + WorldEdit we = WorldEdit.getInstance(); + FabricPlayer player = adaptPlayer((ServerPlayerEntity) playerEntity); + FabricWorld localWorld = getWorld(world); + Location pos = new Location(localWorld, + blockHitResult.getBlockPos().getX(), + blockHitResult.getBlockPos().getY(), + blockHitResult.getBlockPos().getZ() + ); + + if (we.handleBlockRightClick(player, pos)) { + return ActionResult.SUCCESS; + } + + if (we.handleRightClick(player)) { + return ActionResult.SUCCESS; + } + + return ActionResult.PASS; + } + + private ActionResult onRightClickAir(PlayerEntity playerEntity, World world, Hand hand) { + if (shouldSkip() || hand == Hand.OFF_HAND || world.isClient) { + return ActionResult.PASS; + } + + WorldEdit we = WorldEdit.getInstance(); + FabricPlayer player = adaptPlayer((ServerPlayerEntity) playerEntity); + + if (we.handleRightClick(player)) { + return ActionResult.SUCCESS; + } + + return ActionResult.PASS; + } + + // TODO Pass empty left click to server + + /** + * Get the configuration. + * + * @return the Fabric configuration + */ + FabricConfiguration getConfig() { + return this.config; + } + + /** + * Get the session for a player. + * + * @param player the player + * @return the session + */ + public LocalSession getSession(ServerPlayerEntity player) { + checkNotNull(player); + return WorldEdit.getInstance().getSessionManager().get(adaptPlayer(player)); + } + + /** + * Get the WorldEdit proxy for the given world. + * + * @param world the world + * @return the WorldEdit world + */ + public FabricWorld getWorld(World world) { + checkNotNull(world); + return new FabricWorld(world); + } + + /** + * Get the WorldEdit proxy for the platform. + * + * @return the WorldEdit platform + */ + public Platform getPlatform() { + return this.platform; + } + + /** + * Get the working directory where WorldEdit's files are stored. + * + * @return the working directory + */ + public File getWorkingDir() { + return this.workingDir.toFile(); + } + + /** + * Get the version of the WorldEdit-Fabric implementation. + * + * @return a version string + */ + String getInternalVersion() { + return container.getMetadata().getVersion().getFriendlyString(); + } + + public void setPermissionsProvider(FabricPermissionsProvider provider) { + this.provider = provider; + } + + public FabricPermissionsProvider getPermissionsProvider() { + return provider; + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/NBTConverter.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/NBTConverter.java new file mode 100644 index 000000000..450dfcb65 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/NBTConverter.java @@ -0,0 +1,252 @@ +/* + * 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.fabric; + +import com.sk89q.jnbt.ByteArrayTag; +import com.sk89q.jnbt.ByteTag; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.DoubleTag; +import com.sk89q.jnbt.EndTag; +import com.sk89q.jnbt.FloatTag; +import com.sk89q.jnbt.IntArrayTag; +import com.sk89q.jnbt.IntTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.LongTag; +import com.sk89q.jnbt.ShortTag; +import com.sk89q.jnbt.StringTag; +import com.sk89q.jnbt.Tag; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * Converts between JNBT and Minecraft NBT classes. + */ +final class NBTConverter { + + private NBTConverter() { + } + + public static net.minecraft.nbt.Tag toNative(Tag tag) { + if (tag instanceof IntArrayTag) { + return toNative((IntArrayTag) tag); + + } else if (tag instanceof ListTag) { + return toNative((ListTag) tag); + + } else if (tag instanceof LongTag) { + return toNative((LongTag) tag); + + } else if (tag instanceof StringTag) { + return toNative((StringTag) tag); + + } else if (tag instanceof IntTag) { + return toNative((IntTag) tag); + + } else if (tag instanceof ByteTag) { + return toNative((ByteTag) tag); + + } else if (tag instanceof ByteArrayTag) { + return toNative((ByteArrayTag) tag); + + } else if (tag instanceof CompoundTag) { + return toNative((CompoundTag) tag); + + } else if (tag instanceof FloatTag) { + return toNative((FloatTag) tag); + + } else if (tag instanceof ShortTag) { + return toNative((ShortTag) tag); + + } else if (tag instanceof DoubleTag) { + return toNative((DoubleTag) tag); + } else { + throw new IllegalArgumentException("Can't convert tag of type " + tag.getClass().getCanonicalName()); + } + } + + public static net.minecraft.nbt.IntArrayTag toNative(IntArrayTag tag) { + int[] value = tag.getValue(); + return new net.minecraft.nbt.IntArrayTag(Arrays.copyOf(value, value.length)); + } + + public static net.minecraft.nbt.ListTag toNative(ListTag tag) { + net.minecraft.nbt.ListTag list = new net.minecraft.nbt.ListTag(); + for (Tag child : tag.getValue()) { + if (child instanceof EndTag) { + continue; + } + list.add(toNative(child)); + } + return list; + } + + public static net.minecraft.nbt.LongTag toNative(LongTag tag) { + return new net.minecraft.nbt.LongTag(tag.getValue()); + } + + public static net.minecraft.nbt.StringTag toNative(StringTag tag) { + return new net.minecraft.nbt.StringTag(tag.getValue()); + } + + public static net.minecraft.nbt.IntTag toNative(IntTag tag) { + return new net.minecraft.nbt.IntTag(tag.getValue()); + } + + public static net.minecraft.nbt.ByteTag toNative(ByteTag tag) { + return new net.minecraft.nbt.ByteTag(tag.getValue()); + } + + public static net.minecraft.nbt.ByteArrayTag toNative(ByteArrayTag tag) { + byte[] value = tag.getValue(); + return new net.minecraft.nbt.ByteArrayTag(Arrays.copyOf(value, value.length)); + } + + public static net.minecraft.nbt.CompoundTag toNative(CompoundTag tag) { + net.minecraft.nbt.CompoundTag compound = new net.minecraft.nbt.CompoundTag(); + for (Entry child : tag.getValue().entrySet()) { + compound.put(child.getKey(), toNative(child.getValue())); + } + return compound; + } + + public static net.minecraft.nbt.FloatTag toNative(FloatTag tag) { + return new net.minecraft.nbt.FloatTag(tag.getValue()); + } + + public static net.minecraft.nbt.ShortTag toNative(ShortTag tag) { + return new net.minecraft.nbt.ShortTag(tag.getValue()); + } + + public static net.minecraft.nbt.DoubleTag toNative(DoubleTag tag) { + return new net.minecraft.nbt.DoubleTag(tag.getValue()); + } + + public static Tag fromNative(net.minecraft.nbt.Tag other) { + if (other instanceof net.minecraft.nbt.IntArrayTag) { + return fromNative((net.minecraft.nbt.IntArrayTag) other); + + } else if (other instanceof net.minecraft.nbt.ListTag) { + return fromNative((net.minecraft.nbt.ListTag) other); + + } else if (other instanceof net.minecraft.nbt.EndTag) { + return fromNative((net.minecraft.nbt.EndTag) other); + + } else if (other instanceof net.minecraft.nbt.LongTag) { + return fromNative((net.minecraft.nbt.LongTag) other); + + } else if (other instanceof net.minecraft.nbt.StringTag) { + return fromNative((net.minecraft.nbt.StringTag) other); + + } else if (other instanceof net.minecraft.nbt.IntTag) { + return fromNative((net.minecraft.nbt.IntTag) other); + + } else if (other instanceof net.minecraft.nbt.ByteTag) { + return fromNative((net.minecraft.nbt.ByteTag) other); + + } else if (other instanceof net.minecraft.nbt.ByteArrayTag) { + return fromNative((net.minecraft.nbt.ByteArrayTag) other); + + } else if (other instanceof net.minecraft.nbt.CompoundTag) { + return fromNative((net.minecraft.nbt.CompoundTag) other); + + } else if (other instanceof net.minecraft.nbt.FloatTag) { + return fromNative((net.minecraft.nbt.FloatTag) other); + + } else if (other instanceof net.minecraft.nbt.ShortTag) { + return fromNative((net.minecraft.nbt.ShortTag) other); + + } else if (other instanceof net.minecraft.nbt.DoubleTag) { + return fromNative((net.minecraft.nbt.DoubleTag) other); + } else { + throw new IllegalArgumentException("Can't convert other of type " + other.getClass().getCanonicalName()); + } + } + + public static IntArrayTag fromNative(net.minecraft.nbt.IntArrayTag other) { + int[] value = other.getIntArray(); + return new IntArrayTag(Arrays.copyOf(value, value.length)); + } + + public static ListTag fromNative(net.minecraft.nbt.ListTag other) { + other = (net.minecraft.nbt.ListTag) other.copy(); + List list = new ArrayList<>(); + Class listClass = StringTag.class; + int tags = other.size(); + for (int i = 0; i < tags; i++) { + Tag child = fromNative(other.remove(0)); + list.add(child); + listClass = child.getClass(); + } + return new ListTag(listClass, list); + } + + public static EndTag fromNative(net.minecraft.nbt.EndTag other) { + return new EndTag(); + } + + public static LongTag fromNative(net.minecraft.nbt.LongTag other) { + return new LongTag(other.getLong()); + } + + public static StringTag fromNative(net.minecraft.nbt.StringTag other) { + return new StringTag(other.asString()); + } + + public static IntTag fromNative(net.minecraft.nbt.IntTag other) { + return new IntTag(other.getInt()); + } + + public static ByteTag fromNative(net.minecraft.nbt.ByteTag other) { + return new ByteTag(other.getByte()); + } + + public static ByteArrayTag fromNative(net.minecraft.nbt.ByteArrayTag other) { + byte[] value = other.getByteArray(); + return new ByteArrayTag(Arrays.copyOf(value, value.length)); + } + + public static CompoundTag fromNative(net.minecraft.nbt.CompoundTag other) { + Set tags = other.getKeys(); + Map map = new HashMap<>(); + for (String tagName : tags) { + map.put(tagName, fromNative(other.getTag(tagName))); + } + return new CompoundTag(map); + } + + public static FloatTag fromNative(net.minecraft.nbt.FloatTag other) { + return new FloatTag(other.getFloat()); + } + + public static ShortTag fromNative(net.minecraft.nbt.ShortTag other) { + return new ShortTag(other.getShort()); + } + + public static DoubleTag fromNative(net.minecraft.nbt.DoubleTag other) { + return new DoubleTag(other.getDouble()); + } + +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/PropertyAdapter.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/PropertyAdapter.java new file mode 100644 index 000000000..fb46415cd --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/PropertyAdapter.java @@ -0,0 +1,70 @@ +/* + * 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.fabric; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.registry.state.Property; + +import java.util.List; +import java.util.Optional; + +class PropertyAdapter> implements Property { + + private final net.minecraft.state.property.Property property; + private final List values; + + public PropertyAdapter(net.minecraft.state.property.Property property) { + this.property = property; + this.values = ImmutableList.copyOf(property.getValues()); + } + + @Override + public String getName() { + return property.getName(); + } + + @Override + public List getValues() { + return values; + } + + @Override + public T getValueFor(String string) throws IllegalArgumentException { + Optional val = property.getValue(string); + checkArgument(val.isPresent(), "%s has no value for %s", getName(), string); + return val.get(); + } + + @Override + public int hashCode() { + return getName().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Property)) { + return false; + } + return getName().equals(((Property) obj).getName()); + } + +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/ThreadSafeCache.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/ThreadSafeCache.java new file mode 100644 index 000000000..491d80638 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/ThreadSafeCache.java @@ -0,0 +1,76 @@ +/* + * 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.fabric; + +import net.fabricmc.fabric.api.event.server.ServerTickCallback; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * Caches data that cannot be accessed from another thread safely. + */ +public class ThreadSafeCache implements ServerTickCallback { + + private static final long REFRESH_DELAY = 1000 * 30; + private static final ThreadSafeCache INSTANCE = new ThreadSafeCache(); + private Set onlineIds = Collections.emptySet(); + private long lastRefresh = 0; + + /** + * Get an concurrent-safe set of UUIDs of online players. + * + * @return a set of UUIDs + */ + public Set getOnlineIds() { + return onlineIds; + } + + @Override + public void tick(MinecraftServer server) { + long now = System.currentTimeMillis(); + + if (now - lastRefresh > REFRESH_DELAY) { + Set onlineIds = new HashSet<>(); + + if (server == null) { + return; + } + for (ServerPlayerEntity player : server.getPlayerManager().getPlayerList()) { + if (player != null) { + onlineIds.add(player.getUuid()); + } + } + + this.onlineIds = new CopyOnWriteArraySet<>(onlineIds); + + lastRefresh = now; + } + } + + public static ThreadSafeCache getInstance() { + return INSTANCE; + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java new file mode 100644 index 000000000..4faec9d9e --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java @@ -0,0 +1,79 @@ +/* + * 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.fabric; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.sk89q.worldedit.math.BlockVector3; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.IntTag; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import javax.annotation.Nullable; + +/** + * Utility methods for setting tile entities in the world. + */ +final class TileEntityUtils { + + private TileEntityUtils() { + } + + /** + * Update the given tag compound with position information. + * + * @param tag the tag + * @param position the position + */ + private static void updateForSet(CompoundTag tag, BlockVector3 position) { + checkNotNull(tag); + checkNotNull(position); + + tag.put("x", new IntTag(position.getBlockX())); + tag.put("y", new IntTag(position.getBlockY())); + tag.put("z", new IntTag(position.getBlockZ())); + } + + /** + * Set a tile entity at the given location using the tile entity ID from + * the tag. + * + * @param world the world + * @param position the position + * @param tag the tag for the tile entity (may be null to do nothing) + */ + static void setTileEntity(World world, BlockVector3 position, @Nullable CompoundTag tag) { + if (tag != null) { + updateForSet(tag, position); + BlockEntity tileEntity = BlockEntity.createFromTag(tag); + if (tileEntity != null) { + world.setBlockEntity(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()), tileEntity); + } + } + } + + public static CompoundTag copyNbtData(BlockEntity tile) { + CompoundTag tag = new CompoundTag(); + tile.toTag(tag); + return tag; + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/WorldEditFakePlayer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/WorldEditFakePlayer.java new file mode 100644 index 000000000..ea65774b7 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/WorldEditFakePlayer.java @@ -0,0 +1,73 @@ +/* + * 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.fabric; + +import com.mojang.authlib.GameProfile; +import net.minecraft.entity.Entity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.network.chat.Component; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.network.ServerPlayerInteractionManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.stat.Stat; +import net.minecraft.world.dimension.DimensionType; + +import java.util.UUID; + +import javax.annotation.Nullable; + +public class WorldEditFakePlayer extends ServerPlayerEntity { + private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); + + public WorldEditFakePlayer(ServerWorld world) { + super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, new ServerPlayerInteractionManager(world)); + } + + @Override + public void tick() { + } + + @Override + public void increaseStat(Stat stat, int incrementer) { + } + + @Override + public void incrementStat(Stat stat) { + } + + @Override + public void sendMessage(Component component) { + } + + @Override + public void addChatMessage(Component component, boolean opt) { + } + + @Nullable + @Override + public Entity changeDimension(DimensionType dimensionType) { + return this; + } + + @Override + public boolean isInvulnerableTo(DamageSource damageSource) { + return true; + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinServerPlayerEntity.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinServerPlayerEntity.java new file mode 100644 index 000000000..fbad989c1 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinServerPlayerEntity.java @@ -0,0 +1,45 @@ +/* + * 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.fabric.mixin; + +import com.mojang.authlib.GameProfile; +import com.sk89q.worldedit.fabric.FabricWorldEdit; +import net.minecraft.container.ContainerListener; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Hand; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayerEntity.class) +public abstract class MixinServerPlayerEntity extends PlayerEntity implements ContainerListener { + + public MixinServerPlayerEntity(World world, GameProfile gameProfile) { + super(world, gameProfile); + } + + @Inject(method = "swingHand", at = @At(value = "HEAD")) + public void onSwing(Hand hand, CallbackInfo injectionInfo) { + FabricWorldEdit.inst.onLeftClickAir(this, this.world, hand); + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/net/handler/WECUIPacketHandler.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/net/handler/WECUIPacketHandler.java new file mode 100644 index 000000000..816d6c76f --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/net/handler/WECUIPacketHandler.java @@ -0,0 +1,61 @@ +/* + * 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.fabric.net.handler; + +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.fabric.FabricAdapter; +import com.sk89q.worldedit.fabric.FabricPlayer; +import com.sk89q.worldedit.fabric.FabricWorldEdit; +import net.fabricmc.fabric.api.network.PacketConsumer; +import net.fabricmc.fabric.api.network.PacketContext; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.packet.CustomPayloadS2CPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.network.packet.CustomPayloadC2SPacket; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +public final class WECUIPacketHandler { + private WECUIPacketHandler() { + } + + public static final Charset UTF_8_CHARSET = StandardCharsets.UTF_8; + private static final Identifier CUI_IDENTIFIER = new Identifier(FabricWorldEdit.MOD_ID, FabricWorldEdit.CUI_PLUGIN_CHANNEL); + + public static void init() { + ServerSidePacketRegistry.INSTANCE.register(CUI_IDENTIFIER, (packetContext, packetByteBuf) -> { + ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer(); + LocalSession session = FabricWorldEdit.inst.getSession(player); + + if (session.hasCUISupport()) { + return; + } + + String text = packetByteBuf.toString(UTF_8_CHARSET); + final FabricPlayer actor = FabricAdapter.adaptPlayer(player); + session.handleCUIInitializationMessage(text, actor); + session.describeCUI(actor); + }); + } +} \ No newline at end of file diff --git a/worldedit-fabric/src/main/resources/assets/worldedit/icon.png b/worldedit-fabric/src/main/resources/assets/worldedit/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..dc269dcf7b17ffb3d5b4ba950c2dda74a3b5c26b GIT binary patch literal 5636 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�v@D{EVq36fj3OY$AQ03_h`Fl*CG)v2XGC^PGR=7O z{$l^i#c2V&AD3yLVqie&B=8xu%U4jf+165lxYgek4iT(jrc#V-Ck8NxjE#~Ra0MX1 zNxCHW_h2+9hq0tdHwv;w#PNt^ZV|vRQ@aibo3H!*qYnjup;TwWRW^mhIWp8iXK-!S zr%Wgmzz9Jm7~vT3U~KncaMy^rQz}qYGZ+RijNJr;p(sV;a;{o79GFT408r!M>~DY+ ztHlp&8bF1n!c-Fw){Hgz{uPUx1+w{!ZCaqHrW1hSGj=BsHedg#04DUiYQ8mbZ<+o6 zoFP-!sr?Tg+kWn)#r}Jjr9iqUfhPy3okubtW`#3#*k|45<48O9^`4fd~G>cI#X z%`nV?nTKJlw>aqAvpYGo+tyWXbKB`L&M0|&0Z(=gh_XJFt!4~8c$MHZ#?yYR;ZJ) z{g?OU`|nxOtQ~j+hN&G~Xad85*9Q=mwVt$jvJx6(%KGUL zhEcB@nBC*arTii5Q8;bhd+W6s)`colTNeL}6NL@13FZ<{HfcDSdIch~?F7;lp`K>M z2nbU%z}F1+84a^5>4TnZ^W;%an(IyqG zVi?@jA`FeecwfU0u>=Nnx24+fm-OI=OWseq4$Y_fD6r z)qf94wXN5cYY8BWm3n-+DVtfu#tax*Zzur6Cd~w3!XTX}WS{Zz`j)ngC4P&DC-ge* zZxmshz;KHv`ciRq6$=rQR2ruOhCmF5L4=kEn3cYd?H5a?1wPZBvc5||vQlatjn!8e z5`ksm^(DN~i_ky?#uXqd`;3nv5SEM(k7sS`Tt%Ri5u6cF1O~)zgkx%xF|DrH=fyr_ z^vj949DFYjpx@vfWWoh6g9z=n7#$cBPO5NK&zu18ZmB+ulMSEovD6R~%Br-5rzn5{ z#SL-Bwy(7f);Ps59yVZ%0x|qWClP&1DGy4}RTBA9Vyc3Lp;cN+2L4!X#k6;hnyktR z$?r*mhlxn=GA`7oyyg+BG(Z3a*W5b=l(5n_sv#^E!XpCU0tKK{c=@mv3SApJS#t`6 zwWGwstn`g)NMa~>msGS(0o@M-%{mhpPC{xFrimhB2{KXbmA+9REWc0$IYM|0h%!D7 zp*tQcG&{3)7;F02OpO8=nXDHCXG?&GfCz(}3O8nB$ekOSQ40ECC&Cy70s?U@5lxT) zw~-HpgFt@H5f~cIdR}^Lj!~yRGAMTdz-$RXQZJ(PMS+&!nmgis7&|}C7}XFK1h`EA ze54etM4;x-N-hnD09+!vLkRpa01PsKQ6RfSY{Ulz!gGU)W-EXbkl+A~WTS7Qi0F13 e@il_R8-E89rZjGhc4GJd0000=0.4.0", + "fabric": "*" + }, + "mixins": [ + "worldedit.mixins.json" + ] +} \ No newline at end of file diff --git a/worldedit-fabric/src/main/resources/pack.mcmeta b/worldedit-fabric/src/main/resources/pack.mcmeta new file mode 100644 index 000000000..b48da3b7d --- /dev/null +++ b/worldedit-fabric/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "WorldEdit Resources", + "pack_format": 4 + } +} \ No newline at end of file diff --git a/worldedit-fabric/src/main/resources/worldedit.mixins.json b/worldedit-fabric/src/main/resources/worldedit.mixins.json new file mode 100644 index 000000000..165bf44ce --- /dev/null +++ b/worldedit-fabric/src/main/resources/worldedit.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "package": "com.sk89q.worldedit.fabric.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "MixinServerPlayerEntity" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index 37f1a67ff..a48ff6256 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -124,7 +124,7 @@ public class ForgePlayer extends AbstractPlayerActor { send = send + "|" + StringUtil.joinString(params, "|"); } PacketBuffer buffer = new PacketBuffer(Unpooled.copiedBuffer(send.getBytes(WECUIPacketHandler.UTF_8_CHARSET))); - SCustomPayloadPlayPacket packet = new SCustomPayloadPlayPacket(new ResourceLocation(ForgeWorldEdit.CUI_PLUGIN_CHANNEL), buffer); + SCustomPayloadPlayPacket packet = new SCustomPayloadPlayPacket(new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL), buffer); this.player.connection.sendPacket(packet); } From efc4d7cba1fdf8af126392db71d9d1122ec1179c Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 27 Jun 2019 18:37:55 -0400 Subject: [PATCH 223/366] [Fabric] Update fabric/yarn versions to 1.14.3. --- worldedit-fabric/build.gradle | 6 +-- .../worldedit/fabric/FabricBiomeRegistry.java | 2 +- .../worldedit/fabric/FabricBlockRegistry.java | 2 +- .../worldedit/fabric/FabricDataFixer.java | 46 +++++++++---------- .../sk89q/worldedit/fabric/FabricPlayer.java | 24 +++++----- .../worldedit/fabric/WorldEditFakePlayer.java | 9 ++-- 6 files changed, 44 insertions(+), 45 deletions(-) diff --git a/worldedit-fabric/build.gradle b/worldedit-fabric/build.gradle index 6045e3679..b27289bf9 100644 --- a/worldedit-fabric/build.gradle +++ b/worldedit-fabric/build.gradle @@ -22,9 +22,9 @@ buildscript { apply plugin: 'eclipse' apply plugin: 'fabric-loom' -def minecraftVersion = "1.14.2" -def fabricVersion = "0.3.0+build.185" -def yarnMappings = "1.14.2+build.7" +def minecraftVersion = "1.14.3" +def fabricVersion = "0.3.0+build.187" +def yarnMappings = "1.14.3+build.1" def loaderVersion = "0.4.8+build.155" configurations.all { Configuration it -> diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBiomeRegistry.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBiomeRegistry.java index fbf883101..692d350e1 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBiomeRegistry.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBiomeRegistry.java @@ -51,7 +51,7 @@ class FabricBiomeRegistry implements BiomeRegistry { @Override public String getName() { - return biome.getTextComponent().getString(); + return biome.getName().asFormattedString(); } } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockRegistry.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockRegistry.java index 1d219c90c..593e95817 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockRegistry.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockRegistry.java @@ -46,7 +46,7 @@ public class FabricBlockRegistry extends BundledBlockRegistry { public String getName(BlockType blockType) { Block block = FabricAdapter.adapt(blockType); if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { - return block.getTextComponent().getFormattedText(); + return block.getName().asFormattedString(); } else { return super.getName(blockType); } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricDataFixer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricDataFixer.java index c04e06840..f307b789c 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricDataFixer.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricDataFixer.java @@ -43,8 +43,8 @@ import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.TextComponent; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; import net.minecraft.util.DyeColor; import net.minecraft.util.Identifier; import net.minecraft.util.JsonHelper; @@ -1839,12 +1839,12 @@ class FabricDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wo if (!"null".equals(s) && !Strings.isNullOrEmpty(s)) { if ((s.charAt(0) != 34 || s.charAt(s.length() - 1) != 34) && (s.charAt(0) != 123 || s.charAt(s.length() - 1) != 125)) { - object = new TextComponent(s); + object = new LiteralText(s); } else { try { - object = JsonHelper.deserialize(DataConverterSignText.a, s, Component.class, true); + object = JsonHelper.deserialize(DataConverterSignText.a, s, Text.class, true); if (object == null) { - object = new TextComponent(""); + object = new LiteralText(""); } } catch (JsonParseException jsonparseexception) { ; @@ -1852,7 +1852,7 @@ class FabricDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wo if (object == null) { try { - object = Component.Serializer.fromJsonString(s); + object = Text.Serializer.fromJson(s); } catch (JsonParseException jsonparseexception1) { ; } @@ -1860,21 +1860,21 @@ class FabricDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wo if (object == null) { try { - object = Component.Serializer.fromLenientJsonString(s); + object = Text.Serializer.fromLenientJson(s); } catch (JsonParseException jsonparseexception2) { ; } } if (object == null) { - object = new TextComponent(s); + object = new LiteralText(s); } } } else { - object = new TextComponent(""); + object = new LiteralText(""); } - nbttaglist.set(i, new StringTag(Component.Serializer.toJsonString((Component) object))); + nbttaglist.set(i, new StringTag(Text.Serializer.toJson((Text) object))); } nbttagcompound1.put("pages", nbttaglist); @@ -2432,18 +2432,18 @@ class FabricDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wo private static class DataConverterSignText implements DataConverter { - public static final Gson a = new GsonBuilder().registerTypeAdapter(Component.class, new JsonDeserializer() { - Component a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { + public static final Gson a = new GsonBuilder().registerTypeAdapter(Text.class, new JsonDeserializer() { + Text a(JsonElement jsonelement, Type type, JsonDeserializationContext jsondeserializationcontext) throws JsonParseException { if (jsonelement.isJsonPrimitive()) { - return new TextComponent(jsonelement.getAsString()); + return new LiteralText(jsonelement.getAsString()); } else if (jsonelement.isJsonArray()) { JsonArray jsonarray = jsonelement.getAsJsonArray(); - Component iTextComponent = null; + Text iTextComponent = null; Iterator iterator = jsonarray.iterator(); while (iterator.hasNext()) { JsonElement jsonelement1 = (JsonElement) iterator.next(); - Component iTextComponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); + Text iTextComponent1 = this.a(jsonelement1, jsonelement1.getClass(), jsondeserializationcontext); if (iTextComponent == null) { iTextComponent = iTextComponent1; @@ -2486,12 +2486,12 @@ class FabricDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wo if (!"null".equals(s1) && !Strings.isNullOrEmpty(s1)) { if ((s1.charAt(0) != 34 || s1.charAt(s1.length() - 1) != 34) && (s1.charAt(0) != 123 || s1.charAt(s1.length() - 1) != 125)) { - object = new TextComponent(s1); + object = new LiteralText(s1); } else { try { - object = JsonHelper.deserialize(DataConverterSignText.a, s1, Component.class, true); + object = JsonHelper.deserialize(DataConverterSignText.a, s1, Text.class, true); if (object == null) { - object = new TextComponent(""); + object = new LiteralText(""); } } catch (JsonParseException jsonparseexception) { ; @@ -2499,7 +2499,7 @@ class FabricDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wo if (object == null) { try { - object = Component.Serializer.fromJsonString(s1); + object = Text.Serializer.fromJson(s1); } catch (JsonParseException jsonparseexception1) { ; } @@ -2507,21 +2507,21 @@ class FabricDataFixer extends DataFixerBuilder implements com.sk89q.worldedit.wo if (object == null) { try { - object = Component.Serializer.fromLenientJsonString(s1); + object = Text.Serializer.fromLenientJson(s1); } catch (JsonParseException jsonparseexception2) { ; } } if (object == null) { - object = new TextComponent(s1); + object = new LiteralText(s1); } } } else { - object = new TextComponent(""); + object = new LiteralText(""); } - nbttagcompound.putString(s, Component.Serializer.toJsonString((Component) object)); + nbttagcompound.putString(s, Text.Serializer.toJson((Text) object)); } } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java index 1944b3063..d96e0f81f 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java @@ -39,24 +39,24 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import io.netty.buffer.Unpooled; -import net.minecraft.ChatFormat; import net.minecraft.block.Block; import net.minecraft.client.network.packet.BlockEntityUpdateS2CPacket; import net.minecraft.client.network.packet.BlockUpdateS2CPacket; import net.minecraft.client.network.packet.CustomPayloadS2CPacket; import net.minecraft.item.ItemStack; -import net.minecraft.network.chat.TextComponent; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import net.minecraft.util.Hand; import net.minecraft.util.Identifier; import net.minecraft.util.PacketByteBuf; import net.minecraft.util.math.BlockPos; +import javax.annotation.Nullable; import java.io.IOException; import java.util.UUID; -import javax.annotation.Nullable; - public class FabricPlayer extends AbstractPlayerActor { // see ClientPlayNetHandler: search for "invalid update packet", lots of hardcoded consts @@ -81,7 +81,7 @@ public class FabricPlayer extends AbstractPlayerActor { @Override public String getName() { - return this.player.getName().getFormattedText(); + return this.player.getName().asFormattedString(); } @Override @@ -130,33 +130,33 @@ public class FabricPlayer extends AbstractPlayerActor { @Override public void printRaw(String msg) { for (String part : msg.split("\n")) { - this.player.sendMessage(new TextComponent(part)); + this.player.sendMessage(new LiteralText(part)); } } @Override public void printDebug(String msg) { - sendColorized(msg, ChatFormat.GRAY); + sendColorized(msg, Formatting.GRAY); } @Override public void print(String msg) { - sendColorized(msg, ChatFormat.LIGHT_PURPLE); + sendColorized(msg, Formatting.LIGHT_PURPLE); } @Override public void printError(String msg) { - sendColorized(msg, ChatFormat.RED); + sendColorized(msg, Formatting.RED); } @Override public void print(Component component) { - this.player.sendMessage(net.minecraft.network.chat.Component.Serializer.fromJsonString(GsonComponentSerializer.INSTANCE.serialize(component))); + this.player.sendMessage(Text.Serializer.fromJson(GsonComponentSerializer.INSTANCE.serialize(component))); } - private void sendColorized(String msg, ChatFormat formatting) { + private void sendColorized(String msg, Formatting formatting) { for (String part : msg.split("\n")) { - TextComponent component = new TextComponent(part); + LiteralText component = new LiteralText(part); component.getStyle().setColor(formatting); this.player.sendMessage(component); } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/WorldEditFakePlayer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/WorldEditFakePlayer.java index ea65774b7..b1dad7904 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/WorldEditFakePlayer.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/WorldEditFakePlayer.java @@ -22,16 +22,15 @@ package com.sk89q.worldedit.fabric; import com.mojang.authlib.GameProfile; import net.minecraft.entity.Entity; import net.minecraft.entity.damage.DamageSource; -import net.minecraft.network.chat.Component; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerInteractionManager; import net.minecraft.server.world.ServerWorld; import net.minecraft.stat.Stat; +import net.minecraft.text.Text; import net.minecraft.world.dimension.DimensionType; -import java.util.UUID; - import javax.annotation.Nullable; +import java.util.UUID; public class WorldEditFakePlayer extends ServerPlayerEntity { private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]"); @@ -53,11 +52,11 @@ public class WorldEditFakePlayer extends ServerPlayerEntity { } @Override - public void sendMessage(Component component) { + public void sendMessage(Text component) { } @Override - public void addChatMessage(Component component, boolean opt) { + public void addChatMessage(Text component, boolean opt) { } @Nullable From 542f87b8f7b991e36710c13b7edca0f6b290e39c Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 28 Jun 2019 15:18:53 -0400 Subject: [PATCH 224/366] Fix infinite loop re-sizing block state internal ID array. --- .../worldedit/internal/block/BlockStateIdAccess.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java index 9b02fab98..172289c39 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java @@ -57,8 +57,12 @@ public final class BlockStateIdAccess { OptionalInt id = getBlockStateId(blockState); if (id.isPresent()) { int i = id.getAsInt(); - while (i >= blockStates.length) { - blockStates = Arrays.copyOf(blockStates, blockStates.length + blockStates.length >> 1); + if (i >= blockStates.length) { + int curLength = blockStates.length; + do { + curLength += curLength >> 1; + } while (i >= curLength); + blockStates = Arrays.copyOf(blockStates, curLength); } BlockState existing = blockStates[i]; checkState(existing == null || existing == blockState, From c0f2557f15268fcd2fa6ab46050990d11a76f2eb Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 28 Jun 2019 15:45:16 -0400 Subject: [PATCH 225/366] Make the selection wand and navigation wand normal tools. (#493) This means users can bind and unbind them to any item, like other tools. By default, the items in config will be automatically bound. After setting a different item via `//selwand` or `//navwand`, that item will subsequently be used for that user. Also add -n to //wand to get a navwand. Also various other tool-related cleanup. --- .../com/sk89q/worldedit/LocalSession.java | 51 ++++-- .../worldedit/command/SelectionCommands.java | 48 ++++-- .../sk89q/worldedit/command/ToolCommands.java | 31 ++++ .../worldedit/command/tool/AreaPickaxe.java | 12 +- .../command/tool/BlockDataCyler.java | 10 +- .../worldedit/command/tool/BlockReplacer.java | 5 +- .../worldedit/command/tool/BlockTool.java | 10 ++ .../worldedit/command/tool/DistanceWand.java | 44 ++--- .../command/tool/DoubleActionBlockTool.java | 10 ++ .../command/tool/DoubleActionTraceTool.java | 9 ++ .../command/tool/FloatingTreeRemover.java | 2 +- .../command/tool/LongRangeBuildTool.java | 4 +- .../command/tool/NavigationWand.java | 68 ++++++++ .../worldedit/command/tool/QueryTool.java | 3 +- .../command/tool/RecursivePickaxe.java | 11 +- .../worldedit/command/tool/SelectionWand.java | 59 +++++++ .../worldedit/command/tool/SinglePickaxe.java | 8 +- .../worldedit/command/tool/TraceTool.java | 9 ++ .../worldedit/command/tool/TreePlanter.java | 4 +- .../extension/platform/PlatformManager.java | 151 +++++------------- .../worldedit/session/SessionManager.java | 36 ++++- 21 files changed, 394 insertions(+), 191 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/NavigationWand.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index c71e7d1aa..46a73b131 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -28,6 +28,8 @@ import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.command.tool.BlockTool; import com.sk89q.worldedit.command.tool.BrushTool; import com.sk89q.worldedit.command.tool.InvalidToolBindException; +import com.sk89q.worldedit.command.tool.NavigationWand; +import com.sk89q.worldedit.command.tool.SelectionWand; import com.sk89q.worldedit.command.tool.SinglePickaxe; import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; @@ -48,7 +50,6 @@ import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.item.ItemType; -import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.snapshot.Snapshot; import javax.annotation.Nullable; @@ -67,11 +68,11 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class LocalSession { - public transient static int MAX_HISTORY_SIZE = 15; + public static transient int MAX_HISTORY_SIZE = 15; // Non-session related fields private transient LocalConfiguration config; - private transient final AtomicBoolean dirty = new AtomicBoolean(); + private final transient AtomicBoolean dirty = new AtomicBoolean(); private transient int failedCuiAttempts = 0; // Session related @@ -80,7 +81,6 @@ public class LocalSession { private transient LinkedList history = new LinkedList<>(); private transient int historyPointer = 0; private transient ClipboardHolder clipboard; - private transient boolean toolControl = true; private transient boolean superPickaxe = false; private transient BlockTool pickaxeMode = new SinglePickaxe(); private transient Map tools = new HashMap<>(); @@ -100,6 +100,8 @@ public class LocalSession { private String lastScript; private RegionSelectorType defaultSelector; private boolean useServerCUI = false; // Save this to not annoy players. + private String wandItem; + private String navWandItem; /** * Construct the object. @@ -387,21 +389,20 @@ public class LocalSession { } /** - * See if tool control is enabled. - * - * @return true if enabled + * @return true always - see deprecation notice + * @deprecated The wand is now a tool that can be bound/unbound. */ + @Deprecated public boolean isToolControlEnabled() { - return toolControl; + return true; } /** - * Change tool control setting. - * - * @param toolControl true to enable tool control + * @param toolControl unused - see deprecation notice + * @deprecated The wand is now a tool that can be bound/unbound. */ + @Deprecated public void setToolControl(boolean toolControl) { - this.toolControl = toolControl; } /** @@ -594,10 +595,13 @@ public class LocalSession { public void setTool(ItemType item, @Nullable Tool tool) throws InvalidToolBindException { if (item.hasBlockType()) { throw new InvalidToolBindException(item, "Blocks can't be used"); - } else if (item == ItemTypes.get(config.wandItem)) { - throw new InvalidToolBindException(item, "Already used for the wand"); - } else if (item == ItemTypes.get(config.navigationWand)) { - throw new InvalidToolBindException(item, "Already used for the navigation wand"); + } + if (tool instanceof SelectionWand) { + this.wandItem = item.getId(); + setDirty(); + } else if (tool instanceof NavigationWand) { + this.navWandItem = item.getId(); + setDirty(); } this.tools.put(item, tool); @@ -954,4 +958,19 @@ public class LocalSession { this.mask = mask; } + /** + * Get the preferred wand item for this user, or {@code null} to use the default + * @return item id of wand item, or {@code null} + */ + public String getWandItem() { + return wandItem; + } + + /** + * Get the preferred navigation wand item for this user, or {@code null} to use the default + * @return item id of nav wand item, or {@code null} + */ + public String getNavWandItem() { + return navWandItem; + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 155385c52..31aba51e9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -25,6 +25,8 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.command.argument.SelectorChoice; +import com.sk89q.worldedit.command.tool.NavigationWand; +import com.sk89q.worldedit.command.tool.SelectionWand; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; @@ -56,9 +58,13 @@ import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.component.CommandListBox; import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.storage.ChunkStore; import org.enginehub.piston.annotation.Command; @@ -246,24 +252,42 @@ public class SelectionCommands { desc = "Get the wand object" ) @CommandPermissions("worldedit.wand") - public void wand(Player player) throws WorldEditException { - player.giveItem(new BaseItemStack(ItemTypes.get(we.getConfiguration().wandItem), 1)); - player.print("Left click: select pos #1; Right click: select pos #2"); + public void wand(Player player, LocalSession session, + @Switch(name = 'n', desc = "Get a navigation wand") boolean navWand) throws WorldEditException { + String wandId = navWand ? session.getNavWandItem() : session.getWandItem(); + if (wandId == null) { + wandId = navWand ? we.getConfiguration().navigationWand : we.getConfiguration().wandItem; + } + ItemType itemType = ItemTypes.get(wandId); + if (itemType == null) { + player.printError("Wand item is mis-configured or disabled."); + return; + } + player.giveItem(new BaseItemStack(itemType, 1)); + if (navWand) { + session.setTool(itemType, new NavigationWand()); + player.print("Left click: jump to location; Right click: pass through walls"); + } else { + session.setTool(itemType, new SelectionWand()); + player.print("Left click: select pos #1; Right click: select pos #2"); + } } @Command( name = "toggleeditwand", - desc = "Toggle functionality of the edit wand" + desc = "Remind the user that the wand is now a tool and can be unbound with /none." ) @CommandPermissions("worldedit.wand.toggle") - public void toggleWand(Player player, LocalSession session) throws WorldEditException { - session.setToolControl(!session.isToolControlEnabled()); - - if (session.isToolControlEnabled()) { - player.print("Edit wand enabled."); - } else { - player.print("Edit wand disabled."); - } + public void toggleWand(Player player) { + player.print(TextComponent.of("The selection wand is now a normal tool. You can disable it with ") + .append(TextComponent.of("/none", TextColor.AQUA).clickEvent( + ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/none"))) + .append(TextComponent.of(" and rebind it to any item with ")) + .append(TextComponent.of("//selwand", TextColor.AQUA).clickEvent( + ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//selwand"))) + .append(TextComponent.of(" or get a new wand with ")) + .append(TextComponent.of("//wand", TextColor.AQUA).clickEvent( + ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//wand")))); } @Command( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 8242cfec9..c3a57a1ad 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -30,7 +30,9 @@ import com.sk89q.worldedit.command.tool.DistanceWand; import com.sk89q.worldedit.command.tool.FloatingTreeRemover; import com.sk89q.worldedit.command.tool.FloodFillTool; import com.sk89q.worldedit.command.tool.LongRangeBuildTool; +import com.sk89q.worldedit.command.tool.NavigationWand; import com.sk89q.worldedit.command.tool.QueryTool; +import com.sk89q.worldedit.command.tool.SelectionWand; import com.sk89q.worldedit.command.tool.TreePlanter; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; @@ -39,6 +41,7 @@ import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.world.item.ItemType; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -61,6 +64,32 @@ public class ToolCommands { player.print("Tool unbound from your current item."); } + @Command( + name = "/selwand", + aliases = "selwand", + desc = "Selection wand tool" + ) + @CommandPermissions("worldedit.selection.pos") + public void selwand(Player player, LocalSession session) throws WorldEditException { + + final ItemType itemType = player.getItemInHand(HandSide.MAIN_HAND).getType(); + session.setTool(itemType, new SelectionWand()); + player.print("Selection wand bound to " + itemType.getName() + "."); + } + + @Command( + name = "/navwand", + aliases = "navwand", + desc = "Navigation wand tool" + ) + @CommandPermissions({"worldedit.command.jumpto.tool", "worldedit.command.thru.tool"}) + public void navwand(Player player, LocalSession session) throws WorldEditException { + + BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); + session.setTool(itemStack.getType(), new NavigationWand()); + player.print("Navigation wand bound to " + itemStack.getType().getName() + "."); + } + @Command( name = "info", desc = "Block information tool" @@ -82,6 +111,7 @@ public class ToolCommands { public void tree(Player player, LocalSession session, @Arg(desc = "Type of tree to generate", def = "tree") TreeGenerator.TreeType type) throws WorldEditException { + BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); session.setTool(itemStack.getType(), new TreePlanter(type)); player.print("Tree tool bound to " + itemStack.getType().getName() + "."); @@ -95,6 +125,7 @@ public class ToolCommands { public void repl(Player player, LocalSession session, @Arg(desc = "The pattern of blocks to place") Pattern pattern) throws WorldEditException { + BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); session.setTool(itemStack.getType(), new BlockReplacer(pattern)); player.print("Block replacer tool bound to " + itemStack.getType().getName() + "."); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java index 35b3a0c3e..662f8d71e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/AreaPickaxe.java @@ -27,6 +27,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -48,18 +49,18 @@ public class AreaPickaxe implements BlockTool { } @Override - public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { int ox = clicked.getBlockX(); int oy = clicked.getBlockY(); int oz = clicked.getBlockZ(); BlockType initialType = clicked.getExtent().getBlock(clicked.toVector().toBlockPoint()).getBlockType(); if (initialType.getMaterial().isAir()) { - return true; + return false; } if (initialType == BlockTypes.BEDROCK && !player.canDestroyBedrock()) { - return true; + return false; } try (EditSession editSession = session.createEditSession(player)) { @@ -74,9 +75,10 @@ public class AreaPickaxe implements BlockTool { continue; } - ((World) clicked.getExtent()).queueBlockBreakEffect(server, pos, initialType, clicked.toVector().toBlockPoint().distanceSq(pos)); - editSession.setBlock(pos, BlockTypes.AIR.getDefaultState()); + + ((World) clicked.getExtent()).queueBlockBreakEffect(server, pos, initialType, + clicked.toVector().toBlockPoint().distanceSq(pos)); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java index 5440a687f..ac3376d8d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockDataCyler.java @@ -50,8 +50,8 @@ public class BlockDataCyler implements DoubleActionBlockTool { private Map> selectedProperties = new HashMap<>(); - private boolean handleCycle(Platform server, LocalConfiguration config, - Player player, LocalSession session, Location clicked, boolean forward) { + private boolean handleCycle(LocalConfiguration config, Player player, LocalSession session, + Location clicked, boolean forward) { World world = (World) clicked.getExtent(); @@ -88,7 +88,7 @@ public class BlockDataCyler implements DoubleActionBlockTool { try { editSession.setBlock(blockPoint, newBlock); - player.print("Value of " + currentProperty.getName() + " is now " + currentProperty.getValues().get(index).toString()); + player.print("Value of " + currentProperty.getName() + " is now " + currentProperty.getValues().get(index)); } catch (MaxChangedBlocksException e) { player.printError("Max blocks change limit reached."); } finally { @@ -110,12 +110,12 @@ public class BlockDataCyler implements DoubleActionBlockTool { @Override public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { - return handleCycle(server, config, player, session, clicked, true); + return handleCycle(config, player, session, clicked, true); } @Override public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { - return handleCycle(server, config, player, session, clicked, false); + return handleCycle(config, player, session, clicked, false); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java index 9fcdf6754..8cc85d705 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java @@ -30,6 +30,7 @@ import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.block.BlockState; /** @@ -49,7 +50,7 @@ public class BlockReplacer implements DoubleActionBlockTool { } @Override - public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { BlockBag bag = session.getBlockBag(player); try (EditSession editSession = session.createEditSession(player)) { @@ -72,7 +73,7 @@ public class BlockReplacer implements DoubleActionBlockTool { @Override - public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { + public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { BlockState targetBlock = player.getWorld().getBlock(clicked.toVector().toBlockPoint()); if (targetBlock != null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java index 139fbd640..0ee513d75 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockTool.java @@ -27,5 +27,15 @@ import com.sk89q.worldedit.util.Location; public interface BlockTool extends Tool { + /** + * Perform the primary action of this tool. + * + * @param server + * @param config + * @param player + * @param session + * @param clicked + * @return true to cancel the original event which triggered this action (if possible) + */ boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java index 48d3dbf7a..781d24f8c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DistanceWand.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.command.tool; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; import com.sk89q.worldedit.function.mask.Mask; @@ -36,46 +35,33 @@ import com.sk89q.worldedit.util.Location; public class DistanceWand extends BrushTool implements DoubleActionTraceTool { public DistanceWand() { - super("worldedit.wand"); - } - - @Override - public boolean canUse(Actor player) { - return player.hasPermission("worldedit.wand"); + super("worldedit.selection.pos"); } @Override public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { - if (session.isToolControlEnabled() && player.hasPermission("worldedit.selection.pos")) { - Location target = getTarget(player); - if (target == null) return true; - - RegionSelector selector = session.getRegionSelector(player.getWorld()); - BlockVector3 blockPoint = target.toVector().toBlockPoint(); - if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) { - selector.explainPrimarySelection(player, session, blockPoint); - } - return true; + Location target = getTarget(player); + if (target == null) return true; + RegionSelector selector = session.getRegionSelector(player.getWorld()); + BlockVector3 blockPoint = target.toVector().toBlockPoint(); + if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) { + selector.explainPrimarySelection(player, session, blockPoint); } - return false; + return true; } @Override public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { - if (session.isToolControlEnabled() && player.hasPermission("worldedit.selection.pos")) { - Location target = getTarget(player); - if (target == null) return true; - - RegionSelector selector = session.getRegionSelector(player.getWorld()); - BlockVector3 blockPoint = target.toVector().toBlockPoint(); - if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) { - selector.explainSecondarySelection(player, session, blockPoint); - } - return true; + Location target = getTarget(player); + if (target == null) return true; + RegionSelector selector = session.getRegionSelector(player.getWorld()); + BlockVector3 blockPoint = target.toVector().toBlockPoint(); + if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) { + selector.explainSecondarySelection(player, session, blockPoint); } - return false; + return true; } private Location getTarget(Player player) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java index 78f1a5f3e..f2c37e99f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionBlockTool.java @@ -30,6 +30,16 @@ import com.sk89q.worldedit.util.Location; */ public interface DoubleActionBlockTool extends BlockTool { + /** + * Perform the secondary action of this block tool. + * + * @param server + * @param config + * @param player + * @param session + * @param clicked + * @return true to cancel the original event which triggered this action (if possible) + */ boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java index dde9cca86..1c9b6f83f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/DoubleActionTraceTool.java @@ -29,6 +29,15 @@ import com.sk89q.worldedit.extension.platform.Platform; */ public interface DoubleActionTraceTool extends TraceTool { + /** + * Perform the secondary function of this tool. + * + * @param server + * @param config + * @param player + * @param session + * @return true to cancel the original event which triggered this action (if possible) + */ boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java index b60ab4dc1..6c644c35e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/FloatingTreeRemover.java @@ -116,7 +116,7 @@ public class FloatingTreeRemover implements BlockTool { * @param origin any point contained in the floating tree * @return a set containing all blocks in the tree/shroom or null if this is not a floating tree/shroom. */ - private Set bfs(World world, BlockVector3 origin) throws MaxChangedBlocksException { + private Set bfs(World world, BlockVector3 origin) { final Set visited = new HashSet<>(); final LinkedList queue = new LinkedList<>(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java index 27011c5ea..66366f0e3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java @@ -65,7 +65,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo eS.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), secondary); } return true; - } catch (MaxChangedBlocksException e) { + } catch (MaxChangedBlocksException ignored) { // one block? eat it } return false; @@ -86,7 +86,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo eS.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), primary); } return true; - } catch (MaxChangedBlocksException e) { + } catch (MaxChangedBlocksException ignored) { // one block? eat it } return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/NavigationWand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/NavigationWand.java new file mode 100644 index 000000000..ca4d12745 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/NavigationWand.java @@ -0,0 +1,68 @@ +/* + * 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.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.util.Location; + +public class NavigationWand implements DoubleActionTraceTool { + @Override + public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + if (!player.hasPermission("worldedit.navigation.jumpto.tool")) { + return false; + } + final int maxDist = config.navigationWandMaxDistance; + if (maxDist <= 0) { + return false; + } + Location pos = player.getSolidBlockTrace(maxDist); + if (pos != null) { + player.findFreePosition(pos); + } else { + player.printError("No block in sight (or too far)!"); + } + return true; + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { + if (!player.hasPermission("worldedit.navigation.thru.tool")) { + return false; + } + final int maxDist = config.navigationWandMaxDistance; + if (maxDist <= 0) { + return false; + } + + if (!player.passThroughForwardWall(Math.max(1, maxDist - 10))) { + player.printError("Nothing to pass through (or too far)!"); + } + return true; + } + + @Override + public boolean canUse(Actor actor) { + return true; // skip check here - checked separately for primary/secondary + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java index ef71569f4..a199b2b7f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java @@ -27,6 +27,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; @@ -41,7 +42,7 @@ public class QueryTool implements BlockTool { } @Override - public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { World world = (World) clicked.getExtent(); EditSession editSession = session.createEditSession(player); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java index e49a17374..50008bd16 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/RecursivePickaxe.java @@ -27,6 +27,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -52,18 +53,18 @@ public class RecursivePickaxe implements BlockTool { } @Override - public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { World world = (World) clicked.getExtent(); BlockVector3 origin = clicked.toVector().toBlockPoint(); BlockType initialType = world.getBlock(origin).getBlockType(); if (initialType.getMaterial().isAir()) { - return true; + return false; } if (initialType == BlockTypes.BEDROCK && !player.canDestroyBedrock()) { - return true; + return false; } try (EditSession editSession = session.createEditSession(player)) { @@ -96,10 +97,10 @@ public class RecursivePickaxe implements BlockTool { return; } - world.queueBlockBreakEffect(server, pos, initialType, distanceSq); - editSession.setBlock(pos, BlockTypes.AIR.getDefaultState()); + world.queueBlockBreakEffect(server, pos, initialType, distanceSq); + recurse(server, editSession, world, pos.add(1, 0, 0), origin, size, initialType, visited); recurse(server, editSession, world, pos.add(-1, 0, 0), diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java new file mode 100644 index 000000000..43b5f1ea0 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java @@ -0,0 +1,59 @@ +/* + * 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.command.tool; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.RegionSelector; +import com.sk89q.worldedit.util.Location; + +public class SelectionWand implements DoubleActionBlockTool { + + @Override + public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { + RegionSelector selector = session.getRegionSelector(player.getWorld()); + + BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); + if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) { + selector.explainPrimarySelection(player, session, blockPoint); + } + return true; + } + + @Override + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { + RegionSelector selector = session.getRegionSelector(player.getWorld()); + BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); + if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) { + selector.explainSecondarySelection(player, session, blockPoint); + } + return true; + } + + @Override + public boolean canUse(Actor actor) { + return actor.hasPermission("worldedit.selection.pos"); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java index 16721d498..6766528f4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SinglePickaxe.java @@ -27,6 +27,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -42,13 +43,12 @@ public class SinglePickaxe implements BlockTool { } @Override - public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) { + public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { World world = (World) clicked.getExtent(); BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); final BlockType blockType = world.getBlock(blockPoint).getBlockType(); - if (blockType == BlockTypes.BEDROCK - && !player.canDestroyBedrock()) { - return true; + if (blockType == BlockTypes.BEDROCK && !player.canDestroyBedrock()) { + return false; } try (EditSession editSession = session.createEditSession(player)) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java index f02801fa5..6f18e2c71 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TraceTool.java @@ -26,5 +26,14 @@ import com.sk89q.worldedit.extension.platform.Platform; public interface TraceTool extends Tool { + /** + * Perform the primary action of this trace tool. + * + * @param server + * @param config + * @param player + * @param session + * @return true to cancel the original event which triggered this action (if possible) + */ boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java index 8c353ed74..ec6e16723 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/TreePlanter.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator; @@ -52,8 +53,9 @@ public class TreePlanter implements BlockTool { try { boolean successful = false; + final BlockVector3 pos = clicked.toVector().add(0, 1, 0).toBlockPoint(); for (int i = 0; i < 10; i++) { - if (treeType.generate(editSession, clicked.toVector().add(0, 1, 0).toBlockPoint())) { + if (treeType.generate(editSession, pos)) { successful = true; break; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index f0289957f..36e36914b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -308,78 +308,52 @@ public class PlatformManager { Actor actor = createProxyActor(event.getCause()); Location location = event.getLocation(); - Vector3 vector = location.toVector(); // At this time, only handle interaction from players - if (actor instanceof Player) { - Player player = (Player) actor; - LocalSession session = worldEdit.getSessionManager().get(actor); + if (!(actor instanceof Player)) { + return; + } + Player player = (Player) actor; + LocalSession session = worldEdit.getSessionManager().get(actor); - Request.reset(); - Request.request().setSession(session); - Request.request().setWorld(player.getWorld()); + Request.reset(); + Request.request().setSession(session); + Request.request().setWorld(player.getWorld()); - try { - if (event.getType() == Interaction.HIT) { - if (session.isToolControlEnabled() && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) { - if (!actor.hasPermission("worldedit.selection.pos")) { - return; - } - - RegionSelector selector = session.getRegionSelector(player.getWorld()); - - BlockVector3 blockPoint = vector.toBlockPoint(); - if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) { - selector.explainPrimarySelection(actor, session, blockPoint); - } - - event.setCancelled(true); - return; - } - - if (session.hasSuperPickAxe() && player.isHoldingPickAxe()) { - final BlockTool superPickaxe = session.getSuperPickaxe(); - if (superPickaxe != null && superPickaxe.canUse(player)) { - event.setCancelled(superPickaxe.actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location)); - return; - } - } - - Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); - if (tool instanceof DoubleActionBlockTool) { - if (tool.canUse(player)) { - ((DoubleActionBlockTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location); + try { + if (event.getType() == Interaction.HIT) { + // superpickaxe is special because its primary interaction is a left click, not a right click + // in addition, it is implicitly bound to all pickaxe items, not just a single tool item + if (session.hasSuperPickAxe() && player.isHoldingPickAxe()) { + final BlockTool superPickaxe = session.getSuperPickaxe(); + if (superPickaxe != null && superPickaxe.canUse(player)) { + if (superPickaxe.actPrimary(queryCapability(Capability.WORLD_EDITING), + getConfiguration(), player, session, location)) { event.setCancelled(true); } - } - - } else if (event.getType() == Interaction.OPEN) { - if (session.isToolControlEnabled() && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().wandItem)) { - if (!actor.hasPermission("worldedit.selection.pos")) { - return; - } - - RegionSelector selector = session.getRegionSelector(player.getWorld()); - BlockVector3 blockPoint = vector.toBlockPoint(); - if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) { - selector.explainSecondarySelection(actor, session, blockPoint); - } - - event.setCancelled(true); return; } - - Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); - if (tool instanceof BlockTool) { - if (tool.canUse(player)) { - ((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location); - event.setCancelled(true); - } - } } - } finally { - Request.reset(); + + Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + if (tool instanceof DoubleActionBlockTool && tool.canUse(player)) { + if (((DoubleActionBlockTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), + getConfiguration(), player, session, location)) { + event.setCancelled(true); + } + } + + } else if (event.getType() == Interaction.OPEN) { + Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); + if (tool instanceof BlockTool && tool.canUse(player)) { + if (((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), + getConfiguration(), player, session, location)) { + event.setCancelled(true); + } + } } + } finally { + Request.reset(); } } @@ -396,63 +370,26 @@ public class PlatformManager { try { switch (event.getInputType()) { case PRIMARY: { - if (player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().navigationWand)) { - if (getConfiguration().navigationWandMaxDistance <= 0) { - return; - } - - if (!player.hasPermission("worldedit.navigation.jumpto.tool")) { - return; - } - - Location pos = player.getSolidBlockTrace(getConfiguration().navigationWandMaxDistance); - if (pos != null) { - player.findFreePosition(pos); - } else { - player.printError("No block in sight (or too far)!"); - } - - event.setCancelled(true); - return; - } - Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); - if (tool instanceof DoubleActionTraceTool) { - if (tool.canUse(player)) { - ((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session); + if (tool instanceof DoubleActionTraceTool && tool.canUse(player)) { + if (((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), + getConfiguration(), player, session)) { event.setCancelled(true); - return; } + return; } break; } case SECONDARY: { - if (player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().navigationWand)) { - if (getConfiguration().navigationWandMaxDistance <= 0) { - return; - } - - if (!player.hasPermission("worldedit.navigation.thru.tool")) { - return; - } - - if (!player.passThroughForwardWall(40)) { - player.printError("Nothing to pass through!"); - } - - event.setCancelled(true); - return; - } - Tool tool = session.getTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); - if (tool instanceof TraceTool) { - if (tool.canUse(player)) { - ((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session); + if (tool instanceof TraceTool && tool.canUse(player)) { + if (((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), + getConfiguration(), player, session)) { event.setCancelled(true); - return; } + return; } break; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index ba2468bd0..6b94d94ed 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -26,6 +26,10 @@ import com.google.common.util.concurrent.MoreExecutors; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.tool.InvalidToolBindException; +import com.sk89q.worldedit.command.tool.NavigationWand; +import com.sk89q.worldedit.command.tool.SelectionWand; +import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent; import com.sk89q.worldedit.session.request.Request; @@ -35,6 +39,8 @@ import com.sk89q.worldedit.session.storage.VoidStore; import com.sk89q.worldedit.util.concurrency.EvenMoreExecutors; import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.world.gamemode.GameModes; +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.item.ItemTypes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,10 +66,12 @@ import static com.google.common.base.Preconditions.checkNotNull; */ public class SessionManager { - public static int EXPIRATION_GRACE = 600000; + public static int EXPIRATION_GRACE = 10 * 60 * 1000; private static final int FLUSH_PERIOD = 1000 * 30; private static final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 5)); private static final Logger log = LoggerFactory.getLogger(SessionManager.class); + private static boolean warnedInvalidTool; + private final Timer timer = new Timer(); private final WorldEdit worldEdit; private final Map sessions = new HashMap<>(); @@ -157,6 +165,19 @@ public class SessionManager { session.setConfiguration(config); session.setBlockChangeLimit(config.defaultChangeLimit); session.setTimeout(config.calculationTimeout); + try { + if (owner.hasPermission("worldedit.selection.pos")) { + setDefaultWand(session.getWandItem(), config.wandItem, session, new SelectionWand()); + } + if (owner.hasPermission("worldedit.command.jumpto.tool") || owner.hasPermission("worldedit.command.thru.tool")) { + setDefaultWand(session.getNavWandItem(), config.navigationWand, session, new NavigationWand()); + } + } catch (InvalidToolBindException e) { + if (!warnedInvalidTool) { + warnedInvalidTool = true; + log.warn("Invalid wand tool set in config. Tool will not be assigned: " + e.getItemType()); + } + } // Remember the session regardless of if it's currently active or not. // And have the SessionTracker FLUSH inactive sessions. @@ -188,6 +209,19 @@ public class SessionManager { return false; } + private void setDefaultWand(String sessionItem, String configItem, LocalSession session, Tool wand) throws InvalidToolBindException { + ItemType wandItem = null; + if (sessionItem != null) { + wandItem = ItemTypes.get(sessionItem); + } + if (wandItem == null) { + wandItem = ItemTypes.get(configItem); + } + if (wandItem != null) { + session.setTool(wandItem, wand); + } + } + /** * Save a map of sessions to disk. * From 096a9e4f9f91e0797af90887559d4b219f16f699 Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Fri, 28 Jun 2019 22:11:24 +0200 Subject: [PATCH 226/366] Paintings are very special (#492) Fixes WORLDEDIT-3429 --- .../function/entity/ExtentEntityCopy.java | 16 +++++++++++++--- .../internal/helper/MCDirections.java | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java index 3c882a18a..cb35b3cea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java @@ -35,6 +35,7 @@ import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.Direction.Flag; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.entity.EntityTypes; /** * Copies entities provided to the function to the provided destination @@ -91,9 +92,18 @@ public class ExtentEntityCopy implements EntityFunction { if (state != null) { Location newLocation; Location location = entity.getLocation(); + // If the entity has stored the location in the NBT data, we use that location + CompoundTag tag = state.getNbtData(); + boolean hasTilePosition = tag != null && tag.containsKey("TileX") && tag.containsKey("TileY") && tag.containsKey("TileZ"); + if (hasTilePosition) { + location = location.setPosition(Vector3.at(tag.asInt("TileX"), tag.asInt("TileY"), tag.asInt("TileZ")).add(0.5, 0.5, 0.5)); + } Vector3 pivot = from.round().add(0.5, 0.5, 0.5); Vector3 newPosition = transform.apply(location.toVector().subtract(pivot)); + if (hasTilePosition) { + newPosition = newPosition.subtract(0.5, 0.5, 0.5); + } Vector3 newDirection; newDirection = transform.isIdentity() ? @@ -142,14 +152,15 @@ public class ExtentEntityCopy implements EntityFunction { .putInt("TileZ", newTilePosition.getBlockZ()); if (hasFacing) { - Direction direction = MCDirections.fromHanging(tag.asInt("Facing")); + boolean isPainting = state.getType() == EntityTypes.PAINTING; // Paintings have different facing values + Direction direction = isPainting ? MCDirections.fromHorizontalHanging(tag.asInt("Facing")) : MCDirections.fromHanging(tag.asInt("Facing")); if (direction != null) { Vector3 vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector3.ZERO)).normalize(); Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL); if (newDirection != null) { - builder.putByte("Facing", (byte) MCDirections.toHanging(newDirection)); + builder.putByte("Facing", (byte) (isPainting ? MCDirections.toHorizontalHanging(newDirection) : MCDirections.toHanging(newDirection))); } } } @@ -160,5 +171,4 @@ public class ExtentEntityCopy implements EntityFunction { return state; } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java index 959e30ae4..1aabf26b1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java @@ -68,6 +68,10 @@ public final class MCDirections { } public static Direction fromPre13Hanging(int i) { + return fromHorizontalHanging(i); + } + + public static Direction fromHorizontalHanging(int i) { switch (i) { case 0: return Direction.SOUTH; @@ -82,6 +86,21 @@ public final class MCDirections { } } + public static int toHorizontalHanging(Direction direction) { + switch (direction) { + case SOUTH: + return 0; + case WEST: + return 1; + case NORTH: + return 2; + case EAST: + return 3; + default: + return 0; + } + } + public static int fromLegacyHanging(byte i) { switch (i) { case 0: return 2; From 2b0a4bab27c1d11493e17e52b007f48711a2b37b Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 28 Jun 2019 15:28:24 -0400 Subject: [PATCH 227/366] Change unknown selector to list to enable suggestions. --- .../sk89q/worldedit/command/SelectionCommands.java | 2 +- .../worldedit/command/argument/EnumConverter.java | 11 ++++++----- .../worldedit/command/argument/SelectorChoice.java | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 31aba51e9..da4e75681 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -582,7 +582,7 @@ public class SelectionCommands { limit.ifPresent(integer -> player.print(integer + " points maximum.")); break; } - case UNKNOWN: + case LIST: default: CommandListBox box = new CommandListBox("Selection modes", null); box.setHidingHelp(true); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java index 14a49b38c..41f8bae07 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java @@ -29,14 +29,15 @@ import org.enginehub.piston.inject.Key; import javax.annotation.Nullable; import java.util.EnumSet; +import java.util.Locale; import java.util.Set; import java.util.function.Function; -public class EnumConverter { +public final class EnumConverter { public static void register(CommandManager commandManager) { commandManager.registerConverter(Key.of(SelectorChoice.class), - basic(SelectorChoice.class, SelectorChoice.UNKNOWN)); + basic(SelectorChoice.class)); commandManager.registerConverter(Key.of(TreeGenerator.TreeType.class), full(TreeGenerator.TreeType.class, t -> ImmutableSet.copyOf(t.lookupKeys), @@ -48,11 +49,11 @@ public class EnumConverter { } private static > ArgumentConverter basic(Class enumClass) { - return full(enumClass, e -> ImmutableSet.of(e.name()), null); + return full(enumClass, e -> ImmutableSet.of(e.name().toLowerCase(Locale.ROOT)), null); } - private static > ArgumentConverter basic(Class enumClass, E unknownValue) { - return full(enumClass, e -> ImmutableSet.of(e.name()), unknownValue); + private static > ArgumentConverter basic(Class enumClass, @Nullable E unknownValue) { + return full(enumClass, e -> ImmutableSet.of(e.name().toLowerCase(Locale.ROOT)), unknownValue); } private static > ArgumentConverter full(Class enumClass, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java index c17c71601..6a4b4b9ae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/SelectorChoice.java @@ -29,5 +29,5 @@ public enum SelectorChoice { CONVEX, HULL, POLYHEDRON, - UNKNOWN + LIST } From 927ae6d0762acc91ded7876c4015f1e650006c68 Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 28 Jun 2019 16:29:21 -0400 Subject: [PATCH 228/366] Allow block replacer to copy TEs. --- .../java/com/sk89q/worldedit/command/tool/BlockReplacer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java index 8cc85d705..b48c8adca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java @@ -31,7 +31,7 @@ import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BaseBlock; /** * A mode that replaces one block. @@ -74,7 +74,7 @@ public class BlockReplacer implements DoubleActionBlockTool { @Override public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { - BlockState targetBlock = player.getWorld().getBlock(clicked.toVector().toBlockPoint()); + BaseBlock targetBlock = player.getWorld().getFullBlock(clicked.toVector().toBlockPoint()); if (targetBlock != null) { pattern = new BlockPattern(targetBlock); From 9136139cfdc81d0f53f20d1d08b1a421bd3a422f Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 28 Jun 2019 17:09:42 -0400 Subject: [PATCH 229/366] Fix pasting leashed entities. (#494) --- .../function/entity/ExtentEntityCopy.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java index cb35b3cea..d72c8313c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java @@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTagBuilder; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; @@ -138,6 +139,23 @@ public class ExtentEntityCopy implements EntityFunction { CompoundTag tag = state.getNbtData(); if (tag != null) { + // Handle leashed entities + Tag leashTag = tag.getValue().get("Leash"); + if (leashTag instanceof CompoundTag) { + CompoundTag leashCompound = (CompoundTag) leashTag; + if (leashCompound.containsKey("X")) { // leashed to a fence + Vector3 tilePosition = Vector3.at(leashCompound.asInt("X"), leashCompound.asInt("Y"), leashCompound.asInt("Z")); + BlockVector3 newLeash = transform.apply(tilePosition.subtract(from)).add(to).toBlockPoint(); + return new BaseEntity(state.getType(), tag.createBuilder() + .put("Leash", leashCompound.createBuilder() + .putInt("X", newLeash.getBlockX()) + .putInt("Y", newLeash.getBlockY()) + .putInt("Z", newLeash.getBlockZ()) + .build() + ).build()); + } + } + // Handle hanging entities (paintings, item frames, etc.) boolean hasTilePosition = tag.containsKey("TileX") && tag.containsKey("TileY") && tag.containsKey("TileZ"); boolean hasFacing = tag.containsKey("Facing"); From b5e895c37ef0985fa9d272cf919b9040dd8e4e32 Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 28 Jun 2019 18:02:06 -0400 Subject: [PATCH 230/366] Update info tool to components. --- .../worldedit/command/tool/QueryTool.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java index a199b2b7f..2c4e8ff87 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/QueryTool.java @@ -22,15 +22,20 @@ package com.sk89q.worldedit.command.tool; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; -import com.sk89q.worldedit.blocks.MobSpawnerBlock; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; +import java.util.OptionalInt; + /** * Looks up information about a block. */ @@ -49,16 +54,21 @@ public class QueryTool implements BlockTool { BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); BaseBlock block = editSession.getFullBlock(blockPoint); - player.print("\u00A79@" + clicked.toVector() + ": " + "\u00A7e" - + block.getBlockType().getName() + "\u00A77" + " (" - + block.toString() + ") " - + "\u00A7f" - + " (" + world.getBlockLightLevel(blockPoint) + "/" + world.getBlockLightLevel(blockPoint.add(0, 1, 0)) + ")"); - - if (block instanceof MobSpawnerBlock) { - player.printRaw("\u00A7e" + "Mob Type: " - + ((MobSpawnerBlock) block).getMobType()); + TextComponent.Builder builder = TextComponent.builder(); + builder.append(TextComponent.of("@" + clicked.toVector().toBlockPoint() + ": ", TextColor.BLUE)); + builder.append(TextComponent.of(block.getBlockType().getName(), TextColor.YELLOW)); + builder.append(TextComponent.of(" (" + block + ") ", TextColor.GRAY) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Block state")))); + final OptionalInt internalId = BlockStateIdAccess.getBlockStateId(block.toImmutableState()); + if (internalId.isPresent()) { + builder.append(TextComponent.of(" (" + internalId.getAsInt() + ") ", TextColor.DARK_GRAY) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Internal ID")))); } + builder.append(TextComponent.of(" (" + world.getBlockLightLevel(blockPoint) + "/" + + world.getBlockLightLevel(blockPoint.add(0, 1, 0)) + ")", TextColor.WHITE) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Block Light/Light Above")))); + + player.print(builder.build()); return true; } From fae44ffaf2e1b8ad919c2ec17f03f6758087a263 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 29 Jun 2019 07:49:09 -0400 Subject: [PATCH 231/366] Re-send type id for cuboid CUI. Works like poly CUI now. CUI in general needs to cleanup :\ --- .../worldedit/regions/selector/CuboidRegionSelector.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java index c9fd982a9..913d4a333 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/selector/CuboidRegionSelector.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIRegion; import com.sk89q.worldedit.internal.cui.SelectionPointEvent; +import com.sk89q.worldedit.internal.cui.SelectionShapeEvent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; @@ -124,7 +125,7 @@ public class CuboidRegionSelector implements RegionSelector, CUIRegion { public boolean selectPrimary(BlockVector3 position, SelectorLimits limits) { checkNotNull(position); - if (position1 != null && position1.equals(position)) { + if (position.equals(position1)) { return false; } @@ -137,7 +138,7 @@ public class CuboidRegionSelector implements RegionSelector, CUIRegion { public boolean selectSecondary(BlockVector3 position, SelectorLimits limits) { checkNotNull(position); - if (position2 != null && position2.equals(position)) { + if (position.equals(position2)) { return false; } @@ -181,6 +182,8 @@ public class CuboidRegionSelector implements RegionSelector, CUIRegion { checkNotNull(player); checkNotNull(session); + session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID())); + if (position1 != null) { session.dispatchCUIEvent(player, new SelectionPointEvent(0, position1, getArea())); } From abbca2ea1890d705b3d3ee6ee5a0cbaab0285694 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 29 Jun 2019 10:35:22 -0400 Subject: [PATCH 232/366] [Docs] Add a more visible tip about //help on the commands page. --- .../sk89q/worldedit/internal/util/DocumentationPrinter.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt index 167d0cb34..d01020439 100644 --- a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt @@ -144,9 +144,13 @@ Commands .. contents:: :local: -.. tip:: +.. note:: Arguments enclosed in ``[ ]`` are optional, those enclosed in ``< >`` are required. + +.. tip:: + + You can access a command listing in-game via the ``//help`` command. """.trim()) permsOutput.appendln(""" From 9cbf8178eab0a329ae40bae3d47084ea814d4754 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 29 Jun 2019 11:11:22 -0400 Subject: [PATCH 233/366] Fix setting player heads with owner name. --- .../com/sk89q/worldedit/blocks/SkullBlock.java | 17 +++++++++-------- .../factory/parser/DefaultBlockParser.java | 1 - 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java index e65ab3ec1..944b4ab42 100644 --- a/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java +++ b/worldedit-core/src/legacy/java/com/sk89q/worldedit/blocks/SkullBlock.java @@ -83,14 +83,15 @@ public class SkullBlock extends BaseBlock { @Override public String getNbtId() { - return "Skull"; + return "skull"; } @Override public CompoundTag getNbtData() { Map values = new HashMap<>(); - if (owner == null) owner = ""; - values.put("ExtraType", new StringTag(owner)); + Map inner = new HashMap<>(); + inner.put("Name", new StringTag(owner)); + values.put("Owner", new CompoundTag(inner)); return new CompoundTag(values); } @@ -105,13 +106,13 @@ public class SkullBlock extends BaseBlock { Tag t; t = values.get("id"); - if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals("Skull")) { - throw new RuntimeException("'Skull' tile entity expected"); + if (!(t instanceof StringTag) || !((StringTag) t).getValue().equals(getNbtId())) { + throw new RuntimeException(String.format("'%s' tile entity expected", getNbtId())); } - t = values.get("ExtraType"); - if (t instanceof StringTag) { - owner = ((StringTag) t).getValue(); + t = values.get("Owner"); + if (t instanceof CompoundTag) { + setOwner(((CompoundTag) t).getValue().get("Name").getValue().toString()); } } } 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 32736265c..5ef91a497 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 @@ -42,7 +42,6 @@ import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockCategories; -import com.sk89q.worldedit.world.block.BlockCategory; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; From 6be77451b659c121bc2c99fac58ccd4b9c5c1c04 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 29 Jun 2019 13:55:58 -0400 Subject: [PATCH 234/366] Correct perms for nav wand binding. --- .../src/main/java/com/sk89q/worldedit/command/ToolCommands.java | 2 +- .../main/java/com/sk89q/worldedit/session/SessionManager.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index c3a57a1ad..469703f03 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -82,7 +82,7 @@ public class ToolCommands { aliases = "navwand", desc = "Navigation wand tool" ) - @CommandPermissions({"worldedit.command.jumpto.tool", "worldedit.command.thru.tool"}) + @CommandPermissions({"worldedit.nagivation.jumpto.tool", "worldedit.nagivation.thru.tool"}) public void navwand(Player player, LocalSession session) throws WorldEditException { BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index 6b94d94ed..8803cdaf0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -169,7 +169,7 @@ public class SessionManager { if (owner.hasPermission("worldedit.selection.pos")) { setDefaultWand(session.getWandItem(), config.wandItem, session, new SelectionWand()); } - if (owner.hasPermission("worldedit.command.jumpto.tool") || owner.hasPermission("worldedit.command.thru.tool")) { + if (owner.hasPermission("worldedit.nagivation.jumpto.tool") || owner.hasPermission("worldedit.nagivation.thru.tool")) { setDefaultWand(session.getNavWandItem(), config.navigationWand, session, new NavigationWand()); } } catch (InvalidToolBindException e) { From 1d1c38887ff0da51ab4d9927e811c9a8c28e4cc4 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 29 Jun 2019 14:15:58 -0400 Subject: [PATCH 235/366] Added `worldedit.setwand` permission required to change wand/navwand. Players without this perm will be stuck with the configuration-defined default wand/navwand items. --- .../main/java/com/sk89q/worldedit/command/ToolCommands.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 469703f03..08fbcde6c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -69,7 +69,7 @@ public class ToolCommands { aliases = "selwand", desc = "Selection wand tool" ) - @CommandPermissions("worldedit.selection.pos") + @CommandPermissions("worldedit.setwand") public void selwand(Player player, LocalSession session) throws WorldEditException { final ItemType itemType = player.getItemInHand(HandSide.MAIN_HAND).getType(); @@ -82,7 +82,7 @@ public class ToolCommands { aliases = "navwand", desc = "Navigation wand tool" ) - @CommandPermissions({"worldedit.nagivation.jumpto.tool", "worldedit.nagivation.thru.tool"}) + @CommandPermissions("worldedit.setwand") public void navwand(Player player, LocalSession session) throws WorldEditException { BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); From 625cbe5e3d7210956111eabd9a7b1f8d3d6067a1 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 30 Jun 2019 00:38:17 -0400 Subject: [PATCH 236/366] Make //count take a mask. Also doc updates, perm fixes. --- .../bukkit/adapter/BukkitImplLoader.java | 2 +- .../java/com/sk89q/worldedit/EditSession.java | 15 ++++++++++++-- .../worldedit/command/GenerationCommands.java | 4 ++-- .../worldedit/command/RegionCommands.java | 2 +- .../worldedit/command/SelectionCommands.java | 20 +++++-------------- .../worldedit/session/SessionManager.java | 2 +- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java index 5d464181f..0dd6003cc 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java @@ -54,7 +54,7 @@ public class BukkitImplLoader { "** will be blank, and so on. There will be no support for entity\n" + "** and block property-related functions.\n" + "**\n" + - "** Please see http://wiki.sk89q.com/wiki/WorldEdit/Bukkit_adapters\n" + + "** Please see https://worldedit.rtfd.io/en/latest/faq/#bukkit-adapters\n" + "**********************************************\n"; /** 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 a0b0a1150..8501ba917 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -786,12 +786,23 @@ public class EditSession implements Extent, AutoCloseable { * * @param region the region * @param searchBlocks the list of blocks to search - * @return the number of blocks that matched the pattern + * @return the number of blocks that matched the block */ public int countBlocks(Region region, Set searchBlocks) { BlockMask mask = new BlockMask(this, searchBlocks); + return countBlocks(region, mask); + } + + /** + * Count the number of blocks of a list of types in a region. + * + * @param region the region + * @param searchMask mask to match + * @return the number of blocks that matched the mask + */ + public int countBlocks(Region region, Mask searchMask) { Counter count = new Counter(); - RegionMaskingFilter filter = new RegionMaskingFilter(mask, count); + RegionMaskingFilter filter = new RegionMaskingFilter(searchMask, count); RegionVisitor visitor = new RegionVisitor(region, filter); Operations.completeBlindly(visitor); // We can't throw exceptions, nor do we expect any return count.getCount(); 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 6c370a1a1..4ae72b9d7 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 @@ -264,7 +264,7 @@ public class GenerationCommands { name = "/generate", aliases = { "/gen", "/g" }, desc = "Generates a shape according to a formula.", - descFooter = "See also https://tinyurl.com/wesyntax." + descFooter = "See also https://tinyurl.com/weexpr." ) @CommandPermissions("worldedit.generation.shape") @Logging(ALL) @@ -325,7 +325,7 @@ public class GenerationCommands { name = "/generatebiome", aliases = { "/genbiome", "/gb" }, desc = "Sets biome according to a formula.", - descFooter = "See also https://tinyurl.com/wesyntax." + descFooter = "See also https://tinyurl.com/weexpr." ) @CommandPermissions("worldedit.generation.shape.biome") @Logging(ALL) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 262cc57f6..0871f8b8b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -374,7 +374,7 @@ public class RegionCommands { desc = "Deforms a selected region with an expression", descFooter = "The expression is executed for each block and is expected\n" + "to modify the variables x, y and z to point to a new block\n" + - "to fetch. See also tinyurl.com/wesyntax." + "to fetch. See also https://tinyurl.com/weexpr" ) @CommandPermissions("worldedit.region.deform") @Logging(ALL) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index da4e75681..b9a064726 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -35,6 +35,7 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.block.BlockDistributionCounter; +import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.internal.annotation.Direction; @@ -452,24 +453,13 @@ public class SelectionCommands { @Command( name = "/count", - desc = "Counts the number of a certain type of block" + desc = "Counts the number of blocks matching a mask" ) @CommandPermissions("worldedit.analysis.count") public void count(Player player, LocalSession session, EditSession editSession, - @Arg(desc = "The block type(s) to count") - String blocks, - @Switch(name = 'f', desc = "Fuzzy, match states using a wildcard") - boolean fuzzy) throws WorldEditException { - ParserContext context = new ParserContext(); - context.setActor(player); - context.setExtent(player.getExtent()); - context.setWorld(player.getWorld()); - context.setSession(session); - context.setRestricted(false); - context.setPreferringWildcard(fuzzy); - - Set searchBlocks = we.getBlockFactory().parseFromListInput(blocks, context); - int count = editSession.countBlocks(session.getSelection(player.getWorld()), searchBlocks); + @Arg(desc = "The mask of blocks to match") + Mask mask) throws WorldEditException { + int count = editSession.countBlocks(session.getSelection(player.getWorld()), mask); player.print("Counted: " + count); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index 8803cdaf0..403d874c5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -169,7 +169,7 @@ public class SessionManager { if (owner.hasPermission("worldedit.selection.pos")) { setDefaultWand(session.getWandItem(), config.wandItem, session, new SelectionWand()); } - if (owner.hasPermission("worldedit.nagivation.jumpto.tool") || owner.hasPermission("worldedit.nagivation.thru.tool")) { + if (owner.hasPermission("worldedit.navigation.jumpto.tool") || owner.hasPermission("worldedit.navigation.thru.tool")) { setDefaultWand(session.getNavWandItem(), config.navigationWand, session, new NavigationWand()); } } catch (InvalidToolBindException e) { From d27daefd3e896aba95beb8454c73659998a7fd19 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 23 Jun 2019 01:03:18 -0700 Subject: [PATCH 237/366] Implement getBlock for chunk batching extent Also improve speed of comparators, by using ::comparingX and bitwise ops. --- .../extent/reorder/ChunkBatchingExtent.java | 66 +++++++++++++++---- .../sk89q/worldedit/math/BlockVector2.java | 33 +++++++--- .../sk89q/worldedit/math/BlockVector3.java | 40 +++++++---- 3 files changed, 108 insertions(+), 31 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java index b8f6082c4..30940e942 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java @@ -19,22 +19,25 @@ package com.sk89q.worldedit.extent.reorder; +import com.google.common.collect.Table; +import com.google.common.collect.TreeBasedTable; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.RunContext; -import com.sk89q.worldedit.function.operation.SetLocatedBlocks; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.collection.LocatedBlockList; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import java.util.Comparator; +import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.SortedMap; -import java.util.TreeMap; +import java.util.Map; +import java.util.Set; /** * A special extent that batches changes into Minecraft chunks. This helps @@ -49,10 +52,12 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent { * in. This allows for file caches to be used while loading the chunk. */ private static final Comparator REGION_OPTIMIZED_SORT = - Comparator.comparing((BlockVector2 vec) -> vec.divide(32), BlockVector2.COMPARING_GRID_ARRANGEMENT) + Comparator.comparing((BlockVector2 vec) -> vec.shr(5), BlockVector2.COMPARING_GRID_ARRANGEMENT) .thenComparing(BlockVector2.COMPARING_GRID_ARRANGEMENT); - private final SortedMap batches = new TreeMap<>(REGION_OPTIMIZED_SORT); + private final Table batches = + TreeBasedTable.create(REGION_OPTIMIZED_SORT, BlockVector3.sortByCoordsYzx()); + private final Set containedBlocks = new HashSet<>(); private boolean enabled; public ChunkBatchingExtent(Extent extent) { @@ -76,16 +81,51 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent { return enabled; } + private BlockVector2 getChunkPos(BlockVector3 location) { + return location.shr(4).toBlockVector2(); + } + + private BlockVector3 getInChunkPos(BlockVector3 location) { + return BlockVector3.at(location.getX() & 15, location.getY(), location.getZ() & 15); + } + @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { if (!enabled) { return getExtent().setBlock(location, block); } - BlockVector2 chunkPos = BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4); - batches.computeIfAbsent(chunkPos, k -> new LocatedBlockList()).add(location, block); + BlockVector2 chunkPos = getChunkPos(location); + BlockVector3 inChunkPos = getInChunkPos(location); + batches.put(chunkPos, inChunkPos, block.toBaseBlock()); + containedBlocks.add(location); return true; } + @Override + public BlockState getBlock(BlockVector3 position) { + BaseBlock internal = getInternalBlock(position); + if (internal != null) { + return internal.toImmutableState(); + } + return super.getBlock(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + BaseBlock internal = getInternalBlock(position); + if (internal != null) { + return internal; + } + return super.getFullBlock(position); + } + + private BaseBlock getInternalBlock(BlockVector3 position) { + if (!containedBlocks.contains(position)) { + return null; + } + return batches.get(getChunkPos(position), getInChunkPos(position)); + } + @Override protected Operation commitBefore() { if (!commitRequired()) { @@ -94,17 +134,21 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent { return new Operation() { // we get modified between create/resume -- only create this on resume to prevent CME - private Iterator batchIterator; + private Iterator> batchIterator; @Override public Operation resume(RunContext run) throws WorldEditException { if (batchIterator == null) { - batchIterator = batches.values().iterator(); + batchIterator = batches.rowMap().values().iterator(); } if (!batchIterator.hasNext()) { return null; } - new SetLocatedBlocks(getExtent(), batchIterator.next()).resume(run); + Map next = batchIterator.next(); + for (Map.Entry block : next.entrySet()) { + getExtent().setBlock(block.getKey(), block.getValue()); + containedBlocks.remove(block.getKey()); + } batchIterator.remove(); return this; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java index 92548fc99..6e2dd17e1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector2.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.math; -import com.google.common.collect.ComparisonChain; import com.sk89q.worldedit.math.transform.AffineTransform; import java.util.Comparator; @@ -28,7 +27,7 @@ import java.util.Comparator; * An immutable 2-dimensional vector. */ public final class BlockVector2 { - + public static final BlockVector2 ZERO = new BlockVector2(0, 0); public static final BlockVector2 UNIT_X = new BlockVector2(1, 0); public static final BlockVector2 UNIT_Z = new BlockVector2(0, 1); @@ -48,12 +47,8 @@ public final class BlockVector2 { * cdef * */ - public static final Comparator COMPARING_GRID_ARRANGEMENT = (a, b) -> { - return ComparisonChain.start() - .compare(a.getBlockZ(), b.getBlockZ()) - .compare(a.getBlockX(), b.getBlockX()) - .result(); - }; + public static final Comparator COMPARING_GRID_ARRANGEMENT = + Comparator.comparingInt(BlockVector2::getZ).thenComparingInt(BlockVector2::getX); public static BlockVector2 at(double x, double z) { return at((int) Math.floor(x), (int) Math.floor(z)); @@ -303,6 +298,27 @@ public final class BlockVector2 { return divide(n, n); } + /** + * Shift all components right. + * + * @param x the value to shift x by + * @param z the value to shift z by + * @return a new vector + */ + public BlockVector2 shr(int x, int z) { + return at(this.x >> x, this.z >> z); + } + + /** + * Shift all components right by {@code n}. + * + * @param n the value to shift by + * @return a new vector + */ + public BlockVector2 shr(int n) { + return shr(n, n); + } + /** * Get the length of the vector. * @@ -532,5 +548,4 @@ public final class BlockVector2 { public String toString() { return "(" + x + ", " + z + ")"; } - } \ No newline at end of file diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index ffb6f6347..71d058bd9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -19,13 +19,12 @@ package com.sk89q.worldedit.math; -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.collect.ComparisonChain; import com.sk89q.worldedit.math.transform.AffineTransform; import java.util.Comparator; +import static com.google.common.base.Preconditions.checkArgument; + /** * An immutable 3-dimensional vector. */ @@ -64,18 +63,15 @@ public final class BlockVector3 { // thread-safe initialization idiom private static final class YzxOrderComparator { - private static final Comparator YZX_ORDER = (a, b) -> { - return ComparisonChain.start() - .compare(a.y, b.y) - .compare(a.z, b.z) - .compare(a.x, b.x) - .result(); - }; + private static final Comparator YZX_ORDER = + Comparator.comparingInt(BlockVector3::getY) + .thenComparingInt(BlockVector3::getZ) + .thenComparingInt(BlockVector3::getX); } /** * Returns a comparator that sorts vectors first by Y, then Z, then X. - * + * *

    * Useful for sorting by chunk block storage order. */ @@ -348,6 +344,28 @@ public final class BlockVector3 { return divide(n, n, n); } + /** + * Shift all components right. + * + * @param x the value to shift x by + * @param y the value to shift y by + * @param z the value to shift z by + * @return a new vector + */ + public BlockVector3 shr(int x, int y, int z) { + return at(this.x >> x, this.y >> y, this.z >> z); + } + + /** + * Shift all components right by {@code n}. + * + * @param n the value to shift by + * @return a new vector + */ + public BlockVector3 shr(int n) { + return shr(n, n, n); + } + /** * Get the length of the vector. * From 99ee32fe8e318d9d3714cfcf283fe86386ffa773 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 4 Jul 2019 11:43:36 -0700 Subject: [PATCH 238/366] Many fixes for buffered extents --- .../java/com/sk89q/worldedit/EditSession.java | 4 +- .../extent/AbstractBufferingExtent.java | 48 +++++++++++++++++++ .../worldedit/extent/buffer/ExtentBuffer.java | 24 +++------- .../extent/reorder/ChunkBatchingExtent.java | 42 +++++----------- .../extent/reorder/MultiStageReorder.java | 23 +++++++-- .../sk89q/worldedit/math/BlockVector3.java | 22 +++++++++ .../util/collection/LocatedBlockList.java | 46 ++++++++++-------- 7 files changed, 136 insertions(+), 73 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java 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 8501ba917..bd0afc352 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -565,12 +565,12 @@ public class EditSession implements Extent, AutoCloseable { @Override public BlockState getBlock(BlockVector3 position) { - return world.getBlock(position); + return bypassNone.getBlock(position); } @Override public BaseBlock getFullBlock(BlockVector3 position) { - return world.getFullBlock(position); + return bypassNone.getFullBlock(position); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java new file mode 100644 index 000000000..c7aead10a --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java @@ -0,0 +1,48 @@ +package com.sk89q.worldedit.extent; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.util.Optional; + +/** + * Base extent class for buffering changes between {@link #setBlock(BlockVector3, BlockStateHolder)} + * and the delegate extent. This class ensures that {@link #getBlock(BlockVector3)} is properly + * handled, by returning buffered blocks. + */ +public abstract class AbstractBufferingExtent extends AbstractDelegateExtent { + /** + * Create a new instance. + * + * @param extent the extent + */ + protected AbstractBufferingExtent(Extent extent) { + super(extent); + } + + @Override + public abstract > boolean setBlock(BlockVector3 location, T block) throws WorldEditException; + + protected final > boolean setDelegateBlock(BlockVector3 location, T block) throws WorldEditException { + return super.setBlock(location, block); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return getBufferedBlock(position) + .map(BaseBlock::toImmutableState) + .orElseGet(() -> super.getBlock(position)); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return getBufferedBlock(position) + .orElseGet(() -> super.getFullBlock(position)); + } + + protected abstract Optional getBufferedBlock(BlockVector3 position); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java index 562f094e5..8a974c6a6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ExtentBuffer.java @@ -21,16 +21,16 @@ package com.sk89q.worldedit.extent.buffer; import com.google.common.collect.Maps; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.AbstractBufferingExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import java.util.Map; +import java.util.Optional; import static com.google.common.base.Preconditions.checkNotNull; @@ -38,7 +38,7 @@ import static com.google.common.base.Preconditions.checkNotNull; * Buffers changes to an {@link Extent} and allows retrieval of the changed blocks, * without modifying the underlying extent. */ -public class ExtentBuffer extends AbstractDelegateExtent { +public class ExtentBuffer extends AbstractBufferingExtent { private final Map buffer = Maps.newHashMap(); private final Mask mask; @@ -67,23 +67,11 @@ public class ExtentBuffer extends AbstractDelegateExtent { } @Override - public BlockState getBlock(BlockVector3 position) { + protected Optional getBufferedBlock(BlockVector3 position) { if (mask.test(position)) { - return getOrDefault(position).toImmutableState(); + return Optional.of(buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos)))); } - return super.getBlock(position); - } - - @Override - public BaseBlock getFullBlock(BlockVector3 position) { - if (mask.test(position)) { - return getOrDefault(position); - } - return super.getFullBlock(position); - } - - private BaseBlock getOrDefault(BlockVector3 position) { - return buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos))); + return Optional.empty(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java index 30940e942..a44017fd1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java @@ -22,14 +22,13 @@ package com.sk89q.worldedit.extent.reorder; import com.google.common.collect.Table; import com.google.common.collect.TreeBasedTable; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.AbstractBufferingExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.RunContext; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import java.util.Comparator; @@ -37,6 +36,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; /** @@ -45,7 +45,7 @@ import java.util.Set; * loaded repeatedly, however it does take more memory due to caching the * blocks. */ -public class ChunkBatchingExtent extends AbstractDelegateExtent { +public class ChunkBatchingExtent extends AbstractBufferingExtent { /** * Comparator optimized for sorting chunks by the region file they reside @@ -92,7 +92,7 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent { @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { if (!enabled) { - return getExtent().setBlock(location, block); + return setDelegateBlock(location, block); } BlockVector2 chunkPos = getChunkPos(location); BlockVector3 inChunkPos = getInChunkPos(location); @@ -102,28 +102,11 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent { } @Override - public BlockState getBlock(BlockVector3 position) { - BaseBlock internal = getInternalBlock(position); - if (internal != null) { - return internal.toImmutableState(); - } - return super.getBlock(position); - } - - @Override - public BaseBlock getFullBlock(BlockVector3 position) { - BaseBlock internal = getInternalBlock(position); - if (internal != null) { - return internal; - } - return super.getFullBlock(position); - } - - private BaseBlock getInternalBlock(BlockVector3 position) { + protected Optional getBufferedBlock(BlockVector3 position) { if (!containedBlocks.contains(position)) { - return null; + return Optional.empty(); } - return batches.get(getChunkPos(position), getInChunkPos(position)); + return Optional.of(batches.get(getChunkPos(position), getInChunkPos(position))); } @Override @@ -134,19 +117,20 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent { return new Operation() { // we get modified between create/resume -- only create this on resume to prevent CME - private Iterator> batchIterator; + private Iterator>> batchIterator; @Override public Operation resume(RunContext run) throws WorldEditException { if (batchIterator == null) { - batchIterator = batches.rowMap().values().iterator(); + batchIterator = batches.rowMap().entrySet().iterator(); } if (!batchIterator.hasNext()) { return null; } - Map next = batchIterator.next(); - for (Map.Entry block : next.entrySet()) { - getExtent().setBlock(block.getKey(), block.getValue()); + Map.Entry> next = batchIterator.next(); + BlockVector3 chunkOffset = next.getKey().toBlockVector3().shl(4); + for (Map.Entry block : next.getValue().entrySet()) { + getExtent().setBlock(block.getKey().add(chunkOffset), block.getValue()); containedBlocks.remove(block.getKey()); } batchIterator.remove(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java index 55ddbcb73..011640709 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java @@ -20,7 +20,7 @@ package com.sk89q.worldedit.extent.reorder; import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.AbstractBufferingExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; @@ -36,13 +36,17 @@ import com.sk89q.worldedit.world.block.BlockTypes; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; /** * Re-orders blocks into several stages. */ -public class MultiStageReorder extends AbstractDelegateExtent implements ReorderingExtent { +public class MultiStageReorder extends AbstractBufferingExtent implements ReorderingExtent { private static final Map priorityMap = new HashMap<>(); @@ -139,6 +143,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder priorityMap.put(BlockTypes.MOVING_PISTON, PlacementPriority.FINAL); } + private final Set containedBlocks = new HashSet<>(); private Map stages = new HashMap<>(); private boolean enabled; @@ -212,7 +217,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { if (!enabled) { - return super.setBlock(location, block); + return setDelegateBlock(location, block); } BlockState existing = getBlock(location); @@ -240,9 +245,21 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder } stages.get(priority).add(location, block); + containedBlocks.add(location); return !existing.equalsFuzzy(block); } + @Override + protected Optional getBufferedBlock(BlockVector3 position) { + if (!containedBlocks.contains(position)) { + return Optional.empty(); + } + return stages.values().stream() + .map(blocks -> blocks.get(position)) + .filter(Objects::nonNull) + .findAny(); + } + @Override public Operation commitBefore() { if (!commitRequired()) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index 71d058bd9..e8192a128 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -366,6 +366,28 @@ public final class BlockVector3 { return shr(n, n, n); } + /** + * Shift all components left. + * + * @param x the value to shift x by + * @param y the value to shift y by + * @param z the value to shift z by + * @return a new vector + */ + public BlockVector3 shl(int x, int y, int z) { + return at(this.x << x, this.y << y, this.z << z); + } + + /** + * Shift all components left by {@code n}. + * + * @param n the value to shift by + * @return a new vector + */ + public BlockVector3 shl(int n) { + return shl(n, n, n); + } + /** * Get the length of the vector. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java index 67280031d..b558a7102 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java @@ -21,68 +21,72 @@ package com.sk89q.worldedit.util.collection; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.LocatedBlock; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.ListIterator; +import java.util.Map; /** * Wrapper around a list of blocks located in the world. */ public class LocatedBlockList implements Iterable { - private final List list; + private final Map map = new LinkedHashMap<>(); public LocatedBlockList() { - list = new ArrayList<>(); } public LocatedBlockList(Collection collection) { - list = new ArrayList<>(collection); + for (LocatedBlock locatedBlock : collection) { + map.put(locatedBlock.getLocation(), locatedBlock); + } } public void add(LocatedBlock setBlockCall) { checkNotNull(setBlockCall); - list.add(setBlockCall); + map.put(setBlockCall.getLocation(), setBlockCall); } public > void add(BlockVector3 location, B block) { add(new LocatedBlock(location, block.toBaseBlock())); } + public boolean containsLocation(BlockVector3 location) { + return map.containsKey(location); + } + + public @Nullable BaseBlock get(BlockVector3 location) { + return map.get(location).getBlock(); + } + public int size() { - return list.size(); + return map.size(); } public void clear() { - list.clear(); + map.clear(); } @Override public Iterator iterator() { - return list.iterator(); + return map.values().iterator(); } public Iterator reverseIterator() { - return new Iterator() { - - private final ListIterator backingIterator = list.listIterator(list.size()); - - @Override - public boolean hasNext() { - return backingIterator.hasPrevious(); - } - - @Override - public LocatedBlock next() { - return backingIterator.previous(); - } - }; + List data = new ArrayList<>(map.values()); + Collections.reverse(data); + return data.iterator(); } } From f2c47f375992c239a1e297664eb2b7e7079b6434 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 4 Jul 2019 11:55:27 -0700 Subject: [PATCH 239/366] License for new class --- .../extent/AbstractBufferingExtent.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java index c7aead10a..7e1b6466a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/AbstractBufferingExtent.java @@ -1,3 +1,22 @@ +/* + * 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.extent; import com.sk89q.worldedit.WorldEditException; From a2b3aabbbf00cf111f034501e51de45500aaddf6 Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 3 Jul 2019 13:01:59 -0400 Subject: [PATCH 240/366] Typo fixes and command clarifications/cleanup. Also re-disable the gradle daemon. It doesn't always play nice with ForgeGradle and hogs ram. --- gradle.properties | 2 +- .../internal/util/DocumentationPrinter.kt | 1 + .../java/com/sk89q/worldedit/WorldEdit.java | 4 +- .../worldedit/command/BrushCommands.java | 2 +- .../worldedit/command/ClipboardCommands.java | 5 +-- .../worldedit/command/SnapshotCommands.java | 43 ++++++++++++++----- .../sk89q/worldedit/command/ToolCommands.java | 4 +- .../pattern/ClipboardPatternParser.java | 2 +- .../world/snapshot/YYMMDDHHIISSParser.java | 6 +-- 9 files changed, 45 insertions(+), 24 deletions(-) diff --git a/gradle.properties b/gradle.properties index d210d4f53..bca9aaf56 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. #org.gradle.jvmargs=-Xmx3G -#org.gradle.daemon=false \ No newline at end of file +org.gradle.daemon=false \ No newline at end of file diff --git a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt index d01020439..768830857 100644 --- a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt @@ -194,6 +194,7 @@ Other Permissions ``worldedit.override.data-cycler``,"Allows cycling non-whitelisted blocks with the data cycler tool." ``worldedit.setnbt``,"Allows setting `extra data `_ on blocks (such as signs, chests, etc)." ``worldedit.report.pastebin``,"Allows uploading report files to pastebin automatically for the ``/worldedit report`` :doc:`command `." + ``worldedit.scripting.execute.``,"Allows using the CraftScript with the given filename." """.trim()) } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index fa60eb72f..7aec0298a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -666,9 +666,9 @@ public final class WorldEdit { try { engine = new RhinoCraftScriptEngine(); - } catch (NoClassDefFoundError e) { + } catch (NoClassDefFoundError ignored) { player.printError("Failed to find an installed script engine."); - player.printError("Please see http://wiki.sk89q.com/wiki/WorldEdit/Installation"); + player.printError("Please see https://worldedit.readthedocs.io/en/latest/usage/other/craftscripts/"); return; } 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 ae27b9505..a5b6290d6 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 @@ -150,7 +150,7 @@ public class BrushCommands { public void clipboardBrush(Player player, LocalSession session, @Switch(name = 'a', desc = "Don't paste air from the clipboard") boolean ignoreAir, - @Switch(name = 'o', desc = "Paste using clipboard origin, instead of being centered at the target location") + @Switch(name = 'o', desc = "Paste starting at the target location, instead of centering on it") boolean usingOrigin, @Switch(name = 'e', desc = "Paste entities if available") boolean pasteEntities, 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 8b0e20a1f..d2b9f7747 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 @@ -92,8 +92,7 @@ public class ClipboardCommands { @Command( name = "/cut", - desc = "Cut the selection to the clipboard", - descFooter = "WARNING: Cutting and pasting entities cannot be undone!" + desc = "Cut the selection to the clipboard" ) @CommandPermissions("worldedit.clipboard.cut") @Logging(REGION) @@ -105,7 +104,7 @@ public class ClipboardCommands { boolean copyEntities, @Switch(name = 'b', desc = "Also copy biomes, source biomes are unaffected") boolean copyBiomes, - @ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "") + @ArgFlag(name = 'm', desc = "Set the exclude mask, non-matching blocks become air", def = "") Mask mask) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java index 643b064b1..30728ed53 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java @@ -28,12 +28,19 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException; import com.sk89q.worldedit.world.snapshot.Snapshot; import com.sk89q.worldedit.world.storage.MissingWorldException; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; import java.io.File; import java.io.IOException; @@ -61,8 +68,8 @@ public class SnapshotCommands { ) @CommandPermissions("worldedit.snapshots.list") public void list(Player player, - @Arg(desc = "# of snapshots to list", def = "5") - int num) throws WorldEditException { + @ArgFlag(name = 'p', desc = "Page of results to return", def = "1") + int page) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); @@ -75,15 +82,7 @@ public class SnapshotCommands { List snapshots = config.snapshotRepo.getSnapshots(true, player.getWorld().getName()); if (!snapshots.isEmpty()) { - - num = Math.min(40, Math.max(5, num)); - - player.print("Snapshots for world: '" + player.getWorld().getName() + "'"); - for (byte i = 0; i < Math.min(num, snapshots.size()); i++) { - player.print((i + 1) + ". " + snapshots.get(i).getName()); - } - - player.print("Use /snap use [snapshot] or /snap use latest."); + player.print(new SnapshotListBox(player.getWorld().getName(), snapshots).create(page)); } else { player.printError("No snapshots are available. See console for details."); @@ -243,4 +242,26 @@ public class SnapshotCommands { } } + private static class SnapshotListBox extends PaginationBox { + private final List snapshots; + + SnapshotListBox(String world, List snapshots) { + super("Snapshots for: " + world, "/snap list -p %page%"); + this.snapshots = snapshots; + } + + @Override + public Component getComponent(int number) { + final Snapshot snapshot = snapshots.get(number); + return TextComponent.of(number + 1 + ". ", TextColor.GOLD) + .append(TextComponent.of(snapshot.getName(), TextColor.LIGHT_PURPLE) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to use"))) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/snap use " + snapshot.getName()))); + } + + @Override + public int getComponentsSize() { + return snapshots.size(); + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 08fbcde6c..6bbd2d853 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -199,9 +199,9 @@ public class ToolCommands { ) @CommandPermissions("worldedit.tool.lrbuild") public void longrangebuildtool(Player player, LocalSession session, - @Arg(desc = "Block to set on left-click") + @Arg(desc = "Pattern to set on left-click") Pattern primary, - @Arg(desc = "Block to set on right-click") + @Arg(desc = "Pattern to set on right-click") Pattern secondary) throws WorldEditException { BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java index 532a981e6..bb131484f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/ClipboardPatternParser.java @@ -43,7 +43,7 @@ public class ClipboardPatternParser extends InputParser { @Override public Stream getSuggestions(String input) { if (input.isEmpty()) { - return Stream.of("#clipoard"); + return Stream.of("#clipboard"); } String[] offsetParts = input.split("@", 2); String firstLower = offsetParts[0].toLowerCase(Locale.ROOT); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java index 3356f71f6..51a8fa393 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/snapshot/YYMMDDHHIISSParser.java @@ -27,13 +27,13 @@ import java.util.regex.Pattern; public class YYMMDDHHIISSParser implements SnapshotDateParser { - protected Pattern patt = + private Pattern datePattern = Pattern.compile("([0-9]+)[^0-9]?([0-9]+)[^0-9]?([0-9]+)[^0-9]?" - + "([0-9]+)[^0-9]?([0-9]+)[^0-9]?([0-9]+)"); + + "([0-9]+)[^0-9]?([0-9]+)[^0-9]?([0-9]+)(\\..*)?"); @Override public Calendar detectDate(File file) { - Matcher matcher = patt.matcher(file.getName()); + Matcher matcher = datePattern.matcher(file.getName()); if (matcher.matches()) { int year = Integer.parseInt(matcher.group(1)); int month = Integer.parseInt(matcher.group(2)); From 508ece9e0f590624aa245bcf166a2fca04e33c66 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 4 Jul 2019 19:33:37 -0400 Subject: [PATCH 241/366] Use pagination for //distr and store results. (#496) --- .../com/sk89q/worldedit/LocalSession.java | 21 +++++ .../worldedit/command/SelectionCommands.java | 64 +++++++------ .../component/BlockDistributionResult.java | 90 +++++++++++++++++++ 3 files changed, 141 insertions(+), 34 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 46a73b131..124b8661a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -47,16 +47,20 @@ import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.regions.selector.RegionSelectorType; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.request.Request; +import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.snapshot.Snapshot; import javax.annotation.Nullable; import java.time.ZoneId; import java.util.Calendar; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.TimeZone; import java.util.concurrent.atomic.AtomicBoolean; @@ -95,6 +99,7 @@ public class LocalSession { private transient ZoneId timezone = ZoneId.systemDefault(); private transient BlockVector3 cuiTemporaryBlock; private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE; + private transient List> lastDistribution; // Saved properties private String lastScript; @@ -973,4 +978,20 @@ public class LocalSession { public String getNavWandItem() { return navWandItem; } + + /** + * Get the last block distribution stored in this session. + * + * @return block distribution or {@code null} + */ + public List> getLastDistribution() { + return lastDistribution == null ? null : Collections.unmodifiableList(lastDistribution); + } + + /** + * Store a block distribution in this session. + */ + public void setLastDistribution(List> dist) { + lastDistribution = dist; + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index b9a064726..d0dd6ef5a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -30,8 +30,8 @@ import com.sk89q.worldedit.command.tool.SelectionWand; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.block.BlockDistributionCounter; @@ -56,14 +56,15 @@ import com.sk89q.worldedit.regions.selector.SphereRegionSelector; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.component.BlockDistributionResult; import com.sk89q.worldedit.util.formatting.component.CommandListBox; +import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; @@ -71,11 +72,11 @@ import com.sk89q.worldedit.world.storage.ChunkStore; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.stream.Stream; import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; @@ -468,21 +469,35 @@ public class SelectionCommands { desc = "Get the distribution of blocks in the selection" ) @CommandPermissions("worldedit.analysis.distr") - public void distr(Player player, LocalSession session, EditSession editSession, + public void distr(Player player, LocalSession session, @Switch(name = 'c', desc = "Get the distribution of the clipboard instead") boolean clipboardDistr, @Switch(name = 'd', desc = "Separate blocks by state") - boolean separateStates) throws WorldEditException { + boolean separateStates, + @ArgFlag(name = 'p', desc = "Gets page from a previous distribution.", def = "") + Integer page) throws WorldEditException { List> distribution; - if (clipboardDistr) { - Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing - BlockDistributionCounter count = new BlockDistributionCounter(clipboard, separateStates); - RegionVisitor visitor = new RegionVisitor(clipboard.getRegion(), count); - Operations.completeBlindly(visitor); - distribution = count.getDistribution(); + if (page == null) { + if (clipboardDistr) { + Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing + BlockDistributionCounter count = new BlockDistributionCounter(clipboard, separateStates); + RegionVisitor visitor = new RegionVisitor(clipboard.getRegion(), count); + Operations.completeBlindly(visitor); + distribution = count.getDistribution(); + } else { + try (EditSession editSession = session.createEditSession(player)) { + distribution = editSession.getBlockDistribution(session.getSelection(player.getWorld()), separateStates); + } + } + session.setLastDistribution(distribution); + page = 1; } else { - distribution = editSession.getBlockDistribution(session.getSelection(player.getWorld()), separateStates); + distribution = session.getLastDistribution(); + if (distribution == null) { + player.printError("No previous distribution."); + return; + } } if (distribution.isEmpty()) { // *Should* always be false @@ -490,28 +505,9 @@ public class SelectionCommands { return; } - // note: doing things like region.getArea is inaccurate for non-cuboids. - int size = distribution.stream().mapToInt(Countable::getAmount).sum(); - player.print("# total blocks: " + size); - - for (Countable c : distribution) { - String name = c.getID().getBlockType().getName(); - String str; - if (separateStates) { - str = String.format("%-7s (%.3f%%) %s (%s)", - String.valueOf(c.getAmount()), - c.getAmount() / (double) size * 100, - name, - c.getID().getAsString()); - } else { - str = String.format("%-7s (%.3f%%) %s (%s)", - String.valueOf(c.getAmount()), - c.getAmount() / (double) size * 100, - name, - c.getID().getBlockType().getId()); - } - player.print(str); - } + final int finalPage = page; + WorldEditAsyncCommandBuilder.createAndSendMessage(player, + () -> new BlockDistributionResult(distribution, separateStates).create(finalPage), null); } @Command( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java new file mode 100644 index 000000000..797557a52 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java @@ -0,0 +1,90 @@ +/* + * 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.util.formatting.component; + +import com.google.common.base.Strings; +import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; + +import java.util.List; + +public class BlockDistributionResult extends PaginationBox { + + private final List> distribution; + private final int totalBlocks; + private final boolean separateStates; + + public BlockDistributionResult(List> distribution, boolean separateStates) { + super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : "")); + this.distribution = distribution; + // note: doing things like region.getArea is inaccurate for non-cuboids. + this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum(); + this.separateStates = separateStates; + setComponentsPerPage(7); + } + + @Override + public Component getComponent(int number) { + Countable c = distribution.get(number); + TextComponent.Builder line = TextComponent.builder(); + + final int count = c.getAmount(); + + final double perc = count / (double) totalBlocks * 100; + final int maxDigits = (int) (Math.log10(totalBlocks) + 1); + final int curDigits = (int) (Math.log10(count) + 1); + line.append(String.format("%s%.3f%% ", perc < 10 ? " " : "", perc), TextColor.GOLD); + final int space = maxDigits - curDigits; + String pad = Strings.repeat(" ", space == 0 ? 2 : 2 * space + 1); + line.append(String.format("%s%s", count, pad), TextColor.YELLOW); + + final BlockState state = c.getID(); + final BlockType blockType = state.getBlockType(); + TextComponent blockName = TextComponent.of(blockType.getName(), TextColor.LIGHT_PURPLE); + TextComponent toolTip; + if (separateStates && state != blockType.getDefaultState()) { + toolTip = TextComponent.of(state.getAsString(), TextColor.GRAY); + blockName = blockName.append(TextComponent.of("*", TextColor.LIGHT_PURPLE)); + } else { + toolTip = TextComponent.of(blockType.getId(), TextColor.GRAY); + } + blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip)); + line.append(blockName); + + return line.build(); + } + + @Override + public int getComponentsSize() { + return distribution.size(); + } + + @Override + public Component create(int page) throws InvalidComponentException { + super.getContents().append(TextComponent.of("Total Block Count: " + totalBlocks, TextColor.GRAY)) + .append(TextComponent.newline()); + return super.create(page); + } +} From 96e2b6c5af6861f0d57c2dc0bee799bb7a981c17 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 4 Jul 2019 01:48:55 -0400 Subject: [PATCH 242/366] First attempt at fixing quoted string oddities. --- .../extension/factory/MaskFactory.java | 11 +++++++++ .../internal/command/CommandArgParser.java | 24 ++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java index 73df7a52d..b4845f35e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/MaskFactory.java @@ -42,6 +42,7 @@ import com.sk89q.worldedit.internal.registry.InputParser; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * A registry of known {@link Mask}s. Provides methods to instantiate @@ -74,6 +75,16 @@ public final class MaskFactory extends AbstractFactory { register(new BiomeMaskParser(worldEdit)); } + @Override + public List getSuggestions(String input) { + final String[] split = input.split(" "); + if (split.length > 1) { + String prev = input.substring(0, input.lastIndexOf(" ")) + " "; + return super.getSuggestions(split[split.length -1]).stream().map(s -> prev + s).collect(Collectors.toList()); + } + return super.getSuggestions(input); + } + @Override public Mask parseFromInput(String input, ParserContext context) throws InputParseException { List masks = new ArrayList<>(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java index c7ce23311..156563bbb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java @@ -67,16 +67,28 @@ public class CommandArgParser { handleQuote(nextPart); } } + if (currentArg.size() > 0) { + finishArg(); // force finish "hanging" args + } return args.build(); } private void handleNormal(Substring part) { - if (part.getSubstring().startsWith("\"")) { - state = State.QUOTE; - currentArg.add(Substring.wrap( - part.getSubstring().substring(1), - part.getStart(), part.getEnd() - )); + final String strPart = part.getSubstring(); + if (strPart.startsWith("\"")) { + if (strPart.endsWith("\"") && strPart.length() > 1) { + currentArg.add(Substring.wrap( + strPart.substring(1, strPart.length() - 1), + part.getStart(), part.getEnd() + )); + finishArg(); + } else { + state = State.QUOTE; + currentArg.add(Substring.wrap( + strPart.substring(1), + part.getStart(), part.getEnd() + )); + } } else { currentArg.add(part); finishArg(); From f0c0eedde7c65403f3274dc3e0d51830de27c155 Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 5 Jul 2019 17:08:18 -0400 Subject: [PATCH 243/366] Fix handling CUI on Forge server. Probably. --- .../forge/net/handler/WECUIPacketHandler.java | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java index 2fd40fa23..8b26e9e33 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/net/handler/WECUIPacketHandler.java @@ -22,13 +22,8 @@ package com.sk89q.worldedit.forge.net.handler; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.forge.ForgePlayer; import com.sk89q.worldedit.forge.ForgeWorldEdit; -import net.minecraft.client.Minecraft; import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.network.ThreadQuickExitException; -import net.minecraft.network.play.server.SCustomPayloadPlayPacket; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.network.NetworkEvent.ClientCustomPayloadEvent; -import net.minecraftforge.fml.network.NetworkEvent.ServerCustomPayloadEvent; import net.minecraftforge.fml.network.event.EventNetworkChannel; import java.nio.charset.Charset; @@ -47,10 +42,9 @@ public final class WECUIPacketHandler { public static void init() { HANDLER.addListener(WECUIPacketHandler::onPacketData); - HANDLER.addListener(WECUIPacketHandler::callProcessPacket); } - public static void onPacketData(ServerCustomPayloadEvent event) { + public static void onPacketData(ClientCustomPayloadEvent event) { ServerPlayerEntity player = event.getSource().get().getSender(); LocalSession session = ForgeWorldEdit.inst.getSession(player); @@ -63,15 +57,5 @@ public final class WECUIPacketHandler { session.handleCUIInitializationMessage(text, actor); session.describeCUI(actor); } - - public static void callProcessPacket(ClientCustomPayloadEvent event) { - try { - new SCustomPayloadPlayPacket( - new ResourceLocation(ForgeWorldEdit.MOD_ID, ForgeWorldEdit.CUI_PLUGIN_CHANNEL), - event.getPayload() - ).processPacket(Minecraft.getInstance().player.connection); - } catch (ThreadQuickExitException ignored) { - } - } } \ No newline at end of file From 3ad80665d8163f336caa805c0c27255ddc65922e Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 6 Jul 2019 00:12:17 -0700 Subject: [PATCH 244/366] Fix gravity brush itself, not EditSession --- .../java/com/sk89q/worldedit/EditSession.java | 4 +- .../command/tool/brush/GravityBrush.java | 64 ++++++++++++------- 2 files changed, 43 insertions(+), 25 deletions(-) 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 bd0afc352..8501ba917 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -565,12 +565,12 @@ public class EditSession implements Extent, AutoCloseable { @Override public BlockState getBlock(BlockVector3 position) { - return bypassNone.getBlock(position); + return world.getBlock(position); } @Override public BaseBlock getFullBlock(BlockVector3 position) { - return bypassNone.getFullBlock(position); + return world.getFullBlock(position); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java index aedcb578c..25c7c1f75 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java @@ -23,44 +23,62 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.util.LocatedBlock; +import com.sk89q.worldedit.util.collection.LocatedBlockList; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.LinkedHashSet; +import java.util.Set; public class GravityBrush implements Brush { private final boolean fullHeight; - + public GravityBrush(boolean fullHeight) { this.fullHeight = fullHeight; } @Override public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { - final double startY = fullHeight ? editSession.getWorld().getMaxY() : position.getBlockY() + size; - for (double x = position.getBlockX() + size; x > position.getBlockX() - size; --x) { - for (double z = position.getBlockZ() + size; z > position.getBlockZ() - size; --z) { - double y = startY; - final List blockTypes = new ArrayList<>(); - for (; y > position.getBlockY() - size; --y) { - final BlockVector3 pt = BlockVector3.at(x, y, z); - final BlockState block = editSession.getBlock(pt); - if (!block.getBlockType().getMaterial().isAir()) { - blockTypes.add(block); - editSession.setBlock(pt, BlockTypes.AIR.getDefaultState()); + double yMax = fullHeight ? editSession.getWorld().getMaxY() : position.getY() + size; + LocatedBlockList column = new LocatedBlockList(); + Set removedBlocks = new LinkedHashSet<>(); + for (double x = position.getX() - size; x <= position.getX() + size; x++) { + for (double z = position.getZ() - size; z <= position.getZ() + size; z++) { + for (double y = position.getY() - size; y <= yMax; y++) { + BlockVector3 newPos = BlockVector3.at(x, y - 1, z); + BlockVector3 pt = BlockVector3.at(x, y, z); + + BaseBlock block = editSession.getFullBlock(pt); + + if (block.getBlockType().getMaterial().isAir()) { + continue; } - } - BlockVector3 pt = BlockVector3.at(x, y, z); - Collections.reverse(blockTypes); - for (int i = 0; i < blockTypes.size();) { - if (editSession.getBlock(pt).getBlockType().getMaterial().isAir()) { - editSession.setBlock(pt, blockTypes.get(i++)); + + if (!removedBlocks.remove(newPos)) { + // we have not moved the block below this one. + // is it free in the edit session? + if (!editSession.getBlock(newPos).getBlockType().getMaterial().isAir()) { + // no -- do not move this block + continue; + } } - pt = pt.add(0, 1, 0); + + column.add(newPos, block); + removedBlocks.add(pt); } + + for (LocatedBlock block : column) { + editSession.setBlock(block.getLocation(), block.getBlock()); + } + + for (BlockVector3 removedBlock : removedBlocks) { + editSession.setBlock(removedBlock, BlockTypes.AIR.getDefaultState()); + } + + column.clear(); + removedBlocks.clear(); } } } From a18f26f8afc9693ff5ace7ad80dd1bdc715cc456 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 6 Jul 2019 09:44:53 -0400 Subject: [PATCH 245/366] Play nicer with naughty plugins. --- .../main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index f311a9e1b..79526882f 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -335,7 +335,11 @@ public class BukkitAdapter { * @return WorldEdit EntityType */ public static EntityType adapt(org.bukkit.entity.EntityType entityType) { - return EntityTypes.get(entityType.getName().toLowerCase(Locale.ROOT)); + final String name = entityType.getName(); + if (name == null) { + return null; + } + return EntityTypes.get(name.toLowerCase(Locale.ROOT)); } public static org.bukkit.entity.EntityType adapt(EntityType entityType) { From 2ee71cc72f3465b4bfe551884d98f53179f306f0 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 6 Jul 2019 15:41:11 -0700 Subject: [PATCH 246/366] Grav brush: move to bottom, not down one --- .../command/tool/brush/GravityBrush.java | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java index 25c7c1f75..edd58c68b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java @@ -46,25 +46,40 @@ public class GravityBrush implements Brush { Set removedBlocks = new LinkedHashSet<>(); for (double x = position.getX() - size; x <= position.getX() + size; x++) { for (double z = position.getZ() - size; z <= position.getZ() + size; z++) { + /* + * Algorithm: + * 1. Find lowest air block in the selection -> $lowestAir = position + * 2. Move the first non-air block above it down to $lowestAir + * 3. Add 1 to $lowestAir's y-coord. + * 4. If more blocks above current position, repeat from 2 + */ + + BlockVector3 lowestAir = null; for (double y = position.getY() - size; y <= yMax; y++) { - BlockVector3 newPos = BlockVector3.at(x, y - 1, z); BlockVector3 pt = BlockVector3.at(x, y, z); BaseBlock block = editSession.getFullBlock(pt); if (block.getBlockType().getMaterial().isAir()) { + if (lowestAir == null) { + // we found the lowest air block + lowestAir = pt; + } continue; } - if (!removedBlocks.remove(newPos)) { - // we have not moved the block below this one. - // is it free in the edit session? - if (!editSession.getBlock(newPos).getBlockType().getMaterial().isAir()) { - // no -- do not move this block - continue; - } + if (lowestAir == null) { + // no place to move the block to + continue; } + BlockVector3 newPos = lowestAir; + // we know the block above must be air, + // since either this block is being moved into it, + // or there has been more air before this block + lowestAir = lowestAir.add(0, 1, 0); + + removedBlocks.remove(newPos); column.add(newPos, block); removedBlocks.add(pt); } From 5a464142ae96ead54068f32fc21048f0f48713ec Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 8 Jul 2019 20:21:31 -0700 Subject: [PATCH 247/366] Shade Rhino and truezip into Forge dist --- worldedit-core/build.gradle | 2 +- worldedit-forge/build.gradle | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index 9ed0f8b2a..a39f678b5 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -17,7 +17,7 @@ configurations.all { Configuration it -> dependencies { compile project(':worldedit-libs:core') compile 'de.schlichtherle:truezip:6.8.3' - compile 'rhino:js:1.7R2' + compile 'org.mozilla:rhino:1.7R5' compile 'org.yaml:snakeyaml:1.9' compile 'com.google.guava:guava:21.0' compile 'com.google.code.findbugs:jsr305:1.3.9' diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 0cddf21e5..920903932 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -82,8 +82,7 @@ processResources { jar { manifest { - attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version": version) + attributes("WorldEdit-Version": version) } } @@ -94,6 +93,8 @@ shadowJar { include(dependency('org.slf4j:slf4j-api')) include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + include(dependency("de.schlichtherle:truezip")) + include(dependency("org.mozilla:rhino")) } } From 05bf211d7301de62b2c7de01189de73a6597adcd Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 8 Jul 2019 20:25:59 -0700 Subject: [PATCH 248/366] Prepare worldedit-libs for shadow upgrade --- worldedit-libs/build.gradle | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index fa57aa1d0..b31760f52 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -13,6 +13,7 @@ dependents of `-core` to compile and work with WorldEdit's API. */ configure(subprojects + project("core:ap")) { + apply plugin: 'java' apply plugin: 'maven' apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'com.jfrog.artifactory' @@ -23,7 +24,8 @@ configure(subprojects + project("core:ap")) { group = rootProject.group + ".worldedit-libs" - tasks.register("jar", ShadowJar) { + tasks.replace("jar", ShadowJar) + tasks.withType(ShadowJar).named("jar").configure { configurations = [project.configurations.shade] classifier = "" @@ -69,11 +71,15 @@ configure(subprojects + project("core:ap")) { } artifacts { - add("default", jar) - add("archives", sourcesJar) + add("default", jar) { + builtBy(jar) + } + add("archives", sourcesJar) { + builtBy(sourcesJar) + } } - tasks.register("install", Upload) { + tasks.withType(Upload).named("install").configure { configuration = configurations.archives repositories.mavenInstaller { pom.version = project.version From c5c6a091fdf4a9662eba928f8081a7ee07208b9c Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 9 Jul 2019 18:21:21 -0700 Subject: [PATCH 249/366] Update to Gradle 5.5 --- gradle.properties | 5 +---- gradle/wrapper/gradle-wrapper.jar | Bin 54413 -> 55616 bytes gradle/wrapper/gradle-wrapper.properties | 3 +-- gradlew | 18 +++++++++++++++++- gradlew.bat | 18 +++++++++++++++++- worldedit-core/build.gradle | 3 ++- 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/gradle.properties b/gradle.properties index bca9aaf56..f7c837830 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1 @@ -# Sets default memory used for gradle commands. Can be overridden by user or command line properties. -# This is required to provide enough memory for the Minecraft decompilation process. -#org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false \ No newline at end of file +org.gradle.jvmargs=-Xmx1G diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 0d4a9516871afd710a9d84d89e31ba77745607bd..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 GIT binary patch literal 55616 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a9534e761..e0c4de36d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Mar 14 00:19:48 PDT 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip diff --git a/gradlew b/gradlew index cccdd3d51..8e25e6c19 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index e95643d6a..24467a141 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index 9ed0f8b2a..9cf070696 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -1,5 +1,5 @@ plugins { - id("net.ltgt.apt") version "0.21" + id("net.ltgt.apt") version "0.21" apply false } apply plugin: 'java-library' @@ -36,6 +36,7 @@ dependencies { } tasks.withType(JavaCompile).configureEach { + dependsOn(":worldedit-libs:build") it.options.compilerArgs.add("-Aarg.name.key.prefix=") } From e87a5559d68c8ba75712a99e304755af8203ae2d Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 14:10:22 -0700 Subject: [PATCH 250/366] Ensure blocks are not moved below world boundary --- .../com/sk89q/worldedit/command/tool/brush/GravityBrush.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java index edd58c68b..08288636e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/GravityBrush.java @@ -42,6 +42,7 @@ public class GravityBrush implements Brush { @Override public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { double yMax = fullHeight ? editSession.getWorld().getMaxY() : position.getY() + size; + double yMin = Math.max(position.getY() - size, 0); LocatedBlockList column = new LocatedBlockList(); Set removedBlocks = new LinkedHashSet<>(); for (double x = position.getX() - size; x <= position.getX() + size; x++) { @@ -55,7 +56,7 @@ public class GravityBrush implements Brush { */ BlockVector3 lowestAir = null; - for (double y = position.getY() - size; y <= yMax; y++) { + for (double y = yMin; y <= yMax; y++) { BlockVector3 pt = BlockVector3.at(x, y, z); BaseBlock block = editSession.getFullBlock(pt); From 59c2a15cdae831c90aa311050705f0d377727a22 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 11:07:00 -0700 Subject: [PATCH 251/366] Further minor cleanup from Gradle 5 change --- build.gradle | 29 ++++++----------------------- settings.gradle | 11 ----------- settings.gradle.kts | 11 +++++++++++ worldedit-forge/build.gradle | 2 +- worldedit-libs/build.gradle | 7 +++---- 5 files changed, 21 insertions(+), 39 deletions(-) delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/build.gradle b/build.gradle index dddd5470e..c3e908d37 100644 --- a/build.gradle +++ b/build.gradle @@ -1,25 +1,8 @@ -buildscript { - repositories { - mavenCentral() - maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } - jcenter() - } - - configurations.all { - resolutionStrategy { - force 'commons-io:commons-io:2.4' - } - } - - dependencies { - classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4' - classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.8.1' - } -} - plugins { id 'net.minecrell.licenser' version '0.4.1' apply false - id "org.ajoberstar.grgit" version "2.3.0" + id "org.ajoberstar.grgit" version "3.1.1" + id "com.github.johnrengelman.shadow" version "5.1.0" + id "com.jfrog.artifactory" version "4.9.7" } println """ @@ -109,7 +92,7 @@ configure(['core', 'bukkit', 'forge', 'sponge', 'fabric'].collect { project(":wo } task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = 'javadoc' + getArchiveClassifier().set('javadoc') from javadoc.destinationDir } @@ -120,7 +103,7 @@ configure(['core', 'bukkit', 'forge', 'sponge', 'fabric'].collect { project(":wo if (name == "worldedit-core" || name == "worldedit-bukkit") { task sourcesJar(type: Jar, dependsOn: classes) { - classifier = 'sources' + getArchiveClassifier().set('sources') from sourceSets.main.allSource } @@ -146,7 +129,7 @@ configure(['core', 'bukkit', 'forge', 'sponge', 'fabric'].collect { project(":wo configure(['bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) { shadowJar { - classifier 'dist' + getArchiveClassifier().set('dist') dependencies { include(project(":worldedit-libs:core")) include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}")) diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index a7c14e8ee..000000000 --- a/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -rootProject.name = 'worldedit' - -include 'worldedit-libs' - -['bukkit', 'core', 'forge', 'sponge', 'fabric'].forEach { - include "worldedit-libs:$it" - include "worldedit-$it" -} -include "worldedit-libs:core:ap" - -include "worldedit-core:doctools" diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 000000000..6da7bedcc --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,11 @@ +rootProject.name = "worldedit" + +include("worldedit-libs") + +listOf("bukkit", "core", "forge", "sponge", "fabric").forEach { + include("worldedit-libs:$it") + include("worldedit-$it") +} +include("worldedit-libs:core:ap") + +include("worldedit-core:doctools") diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 920903932..0c389e66f 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -108,7 +108,7 @@ afterEvaluate { task deobfJar(type: Jar) { from sourceSets.main.output - classifier = 'dev' + getArchiveClassifier().set("dev") } artifacts { diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index b31760f52..cc3c681a0 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -13,7 +13,7 @@ dependents of `-core` to compile and work with WorldEdit's API. */ configure(subprojects + project("core:ap")) { - apply plugin: 'java' + apply plugin: 'java-base' apply plugin: 'maven' apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'com.jfrog.artifactory' @@ -24,8 +24,7 @@ configure(subprojects + project("core:ap")) { group = rootProject.group + ".worldedit-libs" - tasks.replace("jar", ShadowJar) - tasks.withType(ShadowJar).named("jar").configure { + tasks.register("jar", ShadowJar) { configurations = [project.configurations.shade] classifier = "" @@ -79,7 +78,7 @@ configure(subprojects + project("core:ap")) { } } - tasks.withType(Upload).named("install").configure { + tasks.register("install", Upload) { configuration = configurations.archives repositories.mavenInstaller { pom.version = project.version From eccbad92e8b2312b02023f28dc5f00f2ac97c066 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 13:13:41 -0700 Subject: [PATCH 252/366] Move away from deprecation, move dependencies towards buildSrc --- build.gradle | 7 +++--- buildSrc/build.gradle.kts | 32 ++++++++++++++++++++++++ worldedit-core/build.gradle | 12 ++++----- worldedit-core/doctools/build.gradle.kts | 2 +- worldedit-fabric/build.gradle | 8 +++--- worldedit-sponge/build.gradle | 11 +------- 6 files changed, 46 insertions(+), 26 deletions(-) create mode 100644 buildSrc/build.gradle.kts diff --git a/build.gradle b/build.gradle index c3e908d37..b39e4ebb3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,7 @@ plugins { - id 'net.minecrell.licenser' version '0.4.1' apply false - id "org.ajoberstar.grgit" version "3.1.1" - id "com.github.johnrengelman.shadow" version "5.1.0" - id "com.jfrog.artifactory" version "4.9.7" + id "org.ajoberstar.grgit" + id "com.github.johnrengelman.shadow" + id "com.jfrog.artifactory" } println """ diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 000000000..658143d8d --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,32 @@ +plugins { + `kotlin-dsl` + kotlin("jvm") version embeddedKotlinVersion +} + +repositories { + jcenter() + gradlePluginPortal() + maven { + name = "Forge Maven" + url = uri("https://files.minecraftforge.net/maven") + } +} + +configurations.all { + resolutionStrategy { + // Fabric needs this. + force("commons-io:commons-io:2.5", "org.ow2.asm:asm:7.1") + } +} + +dependencies { + implementation(gradleApi()) + implementation("gradle.plugin.net.minecrell:licenser:0.4.1") + implementation("org.ajoberstar.grgit:grgit-gradle:3.1.1") + implementation("com.github.jengelman.gradle.plugins:shadow:5.1.0") + implementation("net.ltgt.apt-eclipse:net.ltgt.apt-eclipse.gradle.plugin:0.21") + implementation("net.ltgt.apt-idea:net.ltgt.apt-idea.gradle.plugin:0.21") + implementation("org.jfrog.buildinfo:build-info-extractor-gradle:4.9.7") + implementation("gradle.plugin.org.spongepowered:spongegradle:0.9.0") + implementation("net.minecraftforge.gradle:ForgeGradle:3.0.130") +} diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index 182702290..41efbff01 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -1,13 +1,11 @@ plugins { - id("net.ltgt.apt") version "0.21" apply false + id("java-library") + id("eclipse") + id("idea") + id("net.ltgt.apt-eclipse") + id("net.ltgt.apt-idea") } -apply plugin: 'java-library' -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'net.ltgt.apt-eclipse' -apply plugin: 'net.ltgt.apt-idea' - configurations.all { Configuration it -> it.resolutionStrategy { ResolutionStrategy rs -> rs.force("com.google.guava:guava:21.0") diff --git a/worldedit-core/doctools/build.gradle.kts b/worldedit-core/doctools/build.gradle.kts index 002f367bd..75a347ece 100644 --- a/worldedit-core/doctools/build.gradle.kts +++ b/worldedit-core/doctools/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.3.31" + kotlin("jvm") version "1.3.41" } tasks.withType { diff --git a/worldedit-fabric/build.gradle b/worldedit-fabric/build.gradle index b27289bf9..6eee60e9e 100644 --- a/worldedit-fabric/build.gradle +++ b/worldedit-fabric/build.gradle @@ -77,7 +77,7 @@ jar { } shadowJar { - classifier = 'dist-dev' + archiveClassifier.set("dist-dev") dependencies { relocate "org.slf4j", "com.sk89q.worldedit.slf4j" relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge" @@ -89,7 +89,7 @@ shadowJar { task deobfJar(type: Jar) { from sourceSets.main.output - classifier = 'dev' + archiveClassifier.set("dev") } artifacts { @@ -97,8 +97,8 @@ artifacts { } task shadowJarRemap(type: RemapJarTask) { - input shadowJar.archivePath - output new File(shadowJar.archivePath.getAbsolutePath().replaceFirst('-dev\\.jar$', ".jar")) + input shadowJar.archiveFile + output new File(shadowJar.archiveFile.get().asFile.getAbsolutePath().replaceFirst('-dev\\.jar$', ".jar")) } shadowJarRemap.dependsOn(shadowJar) diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle index a745869b6..8d6633de2 100644 --- a/worldedit-sponge/build.gradle +++ b/worldedit-sponge/build.gradle @@ -1,14 +1,5 @@ -buildscript { - repositories { - mavenCentral() - maven { url = "https://files.minecraftforge.net/maven" } - maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" } - jcenter() - } -} - plugins { - id 'org.spongepowered.plugin' version '0.9.0' + id("org.spongepowered.plugin") } repositories { From 19802e478ce3e9c08c500076041f4c75d5820825 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 16:33:21 -0700 Subject: [PATCH 253/366] Re-write root and libs to Kotlin DSL --- build.gradle | 141 ----------------- build.gradle.kts | 28 ++++ buildSrc/src/main/kotlin/ArtifactoryConfig.kt | 40 +++++ buildSrc/src/main/kotlin/CommonConfig.kt | 18 +++ buildSrc/src/main/kotlin/GradleExtras.kt | 6 + buildSrc/src/main/kotlin/LibsConfig.kt | 98 ++++++++++++ buildSrc/src/main/kotlin/PlatformConfig.kt | 101 ++++++++++++ buildSrc/src/main/kotlin/Versions.kt | 5 + gradle.properties | 3 + worldedit-bukkit/build.gradle | 2 + worldedit-core/build.gradle | 2 + worldedit-fabric/build.gradle | 3 + worldedit-forge/build.gradle | 14 +- worldedit-libs/README.md | 9 ++ worldedit-libs/build.gradle | 145 ------------------ worldedit-libs/bukkit/build.gradle.kts | 11 ++ worldedit-libs/core/ap/build.gradle.kts | 6 + worldedit-libs/core/build.gradle.kts | 16 ++ worldedit-libs/fabric/build.gradle.kts | 1 + worldedit-libs/forge/build.gradle.kts | 1 + worldedit-libs/sponge/build.gradle.kts | 11 ++ worldedit-sponge/build.gradle | 3 + 22 files changed, 366 insertions(+), 298 deletions(-) delete mode 100644 build.gradle create mode 100644 build.gradle.kts create mode 100644 buildSrc/src/main/kotlin/ArtifactoryConfig.kt create mode 100644 buildSrc/src/main/kotlin/CommonConfig.kt create mode 100644 buildSrc/src/main/kotlin/GradleExtras.kt create mode 100644 buildSrc/src/main/kotlin/LibsConfig.kt create mode 100644 buildSrc/src/main/kotlin/PlatformConfig.kt create mode 100644 buildSrc/src/main/kotlin/Versions.kt create mode 100644 worldedit-libs/README.md create mode 100644 worldedit-libs/bukkit/build.gradle.kts create mode 100644 worldedit-libs/core/ap/build.gradle.kts create mode 100644 worldedit-libs/core/build.gradle.kts create mode 100644 worldedit-libs/fabric/build.gradle.kts create mode 100644 worldedit-libs/forge/build.gradle.kts create mode 100644 worldedit-libs/sponge/build.gradle.kts diff --git a/build.gradle b/build.gradle deleted file mode 100644 index b39e4ebb3..000000000 --- a/build.gradle +++ /dev/null @@ -1,141 +0,0 @@ -plugins { - id "org.ajoberstar.grgit" - id "com.github.johnrengelman.shadow" - id "com.jfrog.artifactory" -} - -println """ -******************************************* - You are building WorldEdit! - - If you encounter trouble: - 1) Read COMPILING.md if you haven't yet - 2) Try running 'build' in a separate Gradle run - 3) Use gradlew and not gradle - 4) If you still need help, ask on Discord! https://discord.gg/enginehub - - Output files will be in [subproject]/build/libs -******************************************* -""" - -allprojects { - group = 'com.sk89q.worldedit' - version = '7.0.1-SNAPSHOT' -} - -if (!project.hasProperty("artifactory_contextUrl")) ext.artifactory_contextUrl = "http://localhost" -if (!project.hasProperty("artifactory_user")) ext.artifactory_user = "guest" -if (!project.hasProperty("artifactory_password")) ext.artifactory_password = "" - -if (!project.hasProperty("gitCommitHash") && !JavaVersion.current().isJava6()) { - try { - def repo = grgit.open() - ext.gitCommitHash = repo.head().abbreviatedId - } catch (Exception e) { - println "Error getting commit hash: " + e.getMessage() - } -} -if (!project.hasProperty("gitCommitHash")) { - ext.gitCommitHash = "no_git_id" -} - -apply plugin: 'com.jfrog.artifactory' -artifactory { - contextUrl = "${artifactory_contextUrl}" - publish { - repository { - repoKey = project.version.contains("SNAPSHOT") ? 'libs-snapshot-local' : 'libs-release-local' - username = "${artifactory_user}" - password = "${artifactory_password}" - maven = true - ivy = false - } - } -} -artifactoryPublish.skip = true - -subprojects { - repositories { - mavenCentral() - maven { url "http://maven.sk89q.com/repo/" } - maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } - } - configurations.all { - resolutionStrategy { - cacheChangingModulesFor 5, 'minutes' - } - } -} - -configure(['core', 'bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) { - apply plugin: 'java' - apply plugin: 'maven' - apply plugin: 'checkstyle' - apply plugin: 'com.github.johnrengelman.shadow' - apply plugin: 'com.jfrog.artifactory' - apply plugin: 'net.minecrell.licenser' - - ext.internalVersion = version + ";" + gitCommitHash - - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - - checkstyle.configFile = new File(rootProject.projectDir, "config/checkstyle/checkstyle.xml") - checkstyle.toolVersion = '7.6.1' - - if (JavaVersion.current().isJava8Compatible()) { - // Java 8 turns on doclint which we fail - tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:none', '-quiet') - } - } - - task javadocJar(type: Jar, dependsOn: javadoc) { - getArchiveClassifier().set('javadoc') - from javadoc.destinationDir - } - - artifacts { - archives jar - archives javadocJar - } - - if (name == "worldedit-core" || name == "worldedit-bukkit") { - task sourcesJar(type: Jar, dependsOn: classes) { - getArchiveClassifier().set('sources') - from sourceSets.main.allSource - } - - artifacts { - archives sourcesJar - } - build.dependsOn(sourcesJar) - } - - build.dependsOn(checkstyleMain) - build.dependsOn(checkstyleTest) - build.dependsOn(javadocJar) - - artifactoryPublish { - publishConfigs('archives') - } - - license { - header = rootProject.file("HEADER.txt") - include '**/*.java' - } -} - -configure(['bukkit', 'forge', 'sponge', 'fabric'].collect { project(":worldedit-$it") }) { - shadowJar { - getArchiveClassifier().set('dist') - dependencies { - include(project(":worldedit-libs:core")) - include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}")) - include(project(":worldedit-core")) - } - exclude 'GradleStart**' - exclude '.cache' - exclude 'LICENSE*' - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..7088d0893 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,28 @@ +import org.ajoberstar.grgit.Grgit + +println(""" +******************************************* + You are building WorldEdit! + + If you encounter trouble: + 1) Read COMPILING.md if you haven't yet + 2) Try running 'build' in a separate Gradle run + 3) Use gradlew and not gradle + 4) If you still need help, ask on Discord! https://discord.gg/enginehub + + Output files will be in [subproject]/build/libs +******************************************* +""") + +applyRootArtifactoryConfig() + +if (!project.hasProperty("gitCommitHash")) { + apply(plugin = "org.ajoberstar.grgit") + ext["gitCommitHash"] = try { + (ext["grgit"] as Grgit).head().abbreviatedId + } catch (e: Exception) { + println("Error getting commit hash: " + e.message) + + "no_git_id" + } +} diff --git a/buildSrc/src/main/kotlin/ArtifactoryConfig.kt b/buildSrc/src/main/kotlin/ArtifactoryConfig.kt new file mode 100644 index 000000000..d19f35238 --- /dev/null +++ b/buildSrc/src/main/kotlin/ArtifactoryConfig.kt @@ -0,0 +1,40 @@ +import org.gradle.api.Project +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.named +import org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention +import org.jfrog.gradle.plugin.artifactory.task.ArtifactoryTask + +private const val ARTIFACTORY_CONTEXT_URL = "artifactory_contextUrl" +private const val ARTIFACTORY_USER = "artifactory_user" +private const val ARTIFACTORY_PASSWORD = "artifactory_password" + +fun Project.applyRootArtifactoryConfig() { + if (!project.hasProperty(ARTIFACTORY_CONTEXT_URL)) ext[ARTIFACTORY_CONTEXT_URL] = "http://localhost" + if (!project.hasProperty(ARTIFACTORY_USER)) ext[ARTIFACTORY_USER] = "guest" + if (!project.hasProperty(ARTIFACTORY_PASSWORD)) ext[ARTIFACTORY_PASSWORD] = "" + + apply(plugin = "com.jfrog.artifactory") + configure { + setContextUrl("${project.property(ARTIFACTORY_CONTEXT_URL)}") + clientConfig.publisher.run { + repoKey = when { + "${project.version}".contains("SNAPSHOT") -> "libs-snapshot-local" + else -> "libs-release-local" + } + username = "${project.property(ARTIFACTORY_USER)}" + password = "${project.property(ARTIFACTORY_PASSWORD)}" + isMaven = true + isIvy = false + } + } + tasks.named("artifactoryPublish") { + isSkip = true + } +} + +fun Project.applyCommonArtifactoryConfig() { + tasks.named("artifactoryPublish") { + publishConfigs("archives") + } +} diff --git a/buildSrc/src/main/kotlin/CommonConfig.kt b/buildSrc/src/main/kotlin/CommonConfig.kt new file mode 100644 index 000000000..e93f4a2dd --- /dev/null +++ b/buildSrc/src/main/kotlin/CommonConfig.kt @@ -0,0 +1,18 @@ +import org.gradle.api.Project +import org.gradle.kotlin.dsl.repositories + +fun Project.applyCommonConfiguration() { + group = rootProject.group + version = rootProject.version + + repositories { + mavenCentral() + maven { url = uri("https://maven.sk89q.com/repo/") } + maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") } + } + configurations.all { + resolutionStrategy { + cacheChangingModulesFor(5, "minutes") + } + } +} diff --git a/buildSrc/src/main/kotlin/GradleExtras.kt b/buildSrc/src/main/kotlin/GradleExtras.kt new file mode 100644 index 000000000..5358f6b37 --- /dev/null +++ b/buildSrc/src/main/kotlin/GradleExtras.kt @@ -0,0 +1,6 @@ +import org.gradle.api.Project +import org.gradle.api.plugins.ExtraPropertiesExtension +import org.gradle.kotlin.dsl.getByType + +val Project.ext: ExtraPropertiesExtension + get() = extensions.getByType() diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt new file mode 100644 index 000000000..c2754d487 --- /dev/null +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -0,0 +1,98 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.gradle.api.Project +import org.gradle.api.artifacts.ModuleDependency +import org.gradle.api.internal.HasConvention +import org.gradle.api.plugins.MavenRepositoryHandlerConvention +import org.gradle.api.tasks.Upload +import org.gradle.api.tasks.bundling.Jar +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.getPlugin +import org.gradle.kotlin.dsl.invoke +import org.gradle.kotlin.dsl.register + +fun Project.applyLibrariesConfiguration() { + applyCommonConfiguration() + apply(plugin = "java-base") + apply(plugin = "maven") + apply(plugin = "com.github.johnrengelman.shadow") + apply(plugin = "com.jfrog.artifactory") + + configurations { + create("shade") + getByName("archives").extendsFrom(getByName("default")) + } + + group = "${rootProject.group}.worldedit-libs" + + tasks.register("jar") { + configurations = listOf(project.configurations["shade"]) + archiveClassifier.set("") + + dependencies { + exclude(dependency("com.google.guava:guava")) + exclude(dependency("com.google.code.gson:gson")) + exclude(dependency("org.checkerframework:checker-qual")) + } + + relocate("net.kyori.text", "com.sk89q.worldedit.util.formatting.text") + } + val altConfigFiles = { artifactType: String -> + val deps = configurations["shade"].incoming.dependencies + .filterIsInstance() + .map { it.copy() } + .map { dependency -> + dependency.artifact { + name = dependency.name + type = artifactType + extension = "jar" + classifier = artifactType + } + dependency + } + + files(configurations.detachedConfiguration(*deps.toTypedArray()) + .resolvedConfiguration.lenientConfiguration.artifacts + .filter { it.classifier == artifactType } + .map { zipTree(it.file) }) + } + tasks.register("sourcesJar") { + from({ + altConfigFiles("sources") + }) + val filePattern = Regex("(.*)net/kyori/text((?:/|$).*)") + val textPattern = Regex("net\\.kyori\\.text") + eachFile { + filter { + it.replaceFirst(textPattern, "com.sk89q.worldedit.util.formatting.text") + } + path = path.replaceFirst(filePattern, "$1com/sk89q/worldedit/util/formatting/text$2") + } + archiveClassifier.set("sources") + } + + tasks.named("assemble").configure { + dependsOn("jar", "sourcesJar") + } + + artifacts { + val jar = tasks.named("jar") + add("default", jar) { + builtBy(jar) + } + val sourcesJar = tasks.named("sourcesJar") + add("archives", sourcesJar) { + builtBy(sourcesJar) + } + } + + tasks.register("install") { + configuration = configurations["archives"] + (repositories as HasConvention).convention.getPlugin().mavenInstaller { + pom.version = project.version.toString() + pom.artifactId = project.name + } + } + + applyCommonArtifactoryConfig() +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt new file mode 100644 index 000000000..85042cc9f --- /dev/null +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -0,0 +1,101 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import net.minecrell.gradle.licenser.LicenseExtension +import org.gradle.api.JavaVersion +import org.gradle.api.Project +import org.gradle.api.plugins.JavaPluginConvention +import org.gradle.api.plugins.quality.CheckstyleExtension +import org.gradle.api.tasks.bundling.Jar +import org.gradle.api.tasks.javadoc.Javadoc +import org.gradle.external.javadoc.CoreJavadocOptions +import org.gradle.kotlin.dsl.apply +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.getByName +import org.gradle.kotlin.dsl.getPlugin +import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.the +import org.gradle.kotlin.dsl.withType +import org.gradle.kotlin.dsl.named + +fun Project.applyPlatformAndCoreConfiguration() { + applyCommonConfiguration() + apply(plugin = "java") + apply(plugin = "maven") + apply(plugin = "checkstyle") + apply(plugin = "com.github.johnrengelman.shadow") + apply(plugin = "com.jfrog.artifactory") + apply(plugin = "net.minecrell.licenser") + + ext["internalVersion"] = "$version;${rootProject.ext["gitCommitHash"]}" + + configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + configure { + configFile = rootProject.file("config/checkstyle/checkstyle.xml") + toolVersion = "7.6.1" + } + + // Java 8 turns on doclint which we fail + tasks.withType().configureEach { + (options as CoreJavadocOptions).addStringOption("Xdoclint:none", "-quiet") + } + + tasks.register("javadocJar") { + dependsOn("javadoc") + archiveClassifier.set("javadoc") + from(tasks.getByName("javadoc").destinationDir) + } + + tasks.named("assemble").configure { + dependsOn("javadocJar") + } + + artifacts { + add("archives", tasks.named("jar")) + add("archives", tasks.named("javadocJar")) + } + + if (name == "worldedit-core" || name == "worldedit-bukkit") { + tasks.register("sourcesJar") { + dependsOn("classes") + archiveClassifier.set("sources") + from(project.the().sourceSets["main"].allSource) + } + + artifacts { + add("archives", tasks.named("sourcesJar")) + } + tasks.named("assemble").configure { + dependsOn("sourcesJar") + } + } + + tasks.named("check").configure { + dependsOn("checkstyleMain", "checkstyleTest") + } + + applyCommonArtifactoryConfig() + + configure { + header = rootProject.file("HEADER.txt") + include("**/*.java") + } +} + +fun Project.applyShadowConfiguration() { + tasks.named("shadowJar") { + archiveClassifier.set("dist") + dependencies { + include(project(":worldedit-libs:core")) + include(project(":worldedit-libs:${project.name.replace("worldedit-", "")}")) + include(project(":worldedit-core")) + } + exclude("GradleStart**") + exclude(".cache") + exclude("LICENSE*") + minimize() + } +} diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt new file mode 100644 index 000000000..fd61ee13b --- /dev/null +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -0,0 +1,5 @@ +object Versions { + const val TEXT = "3.0.1" + const val TEXT_EXTRAS = "3.0.2" + const val PISTON = "0.4.2" +} diff --git a/gradle.properties b/gradle.properties index f7c837830..a2cc53d8e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,4 @@ +group=com.sk89q.worldedit +version=7.0.1-SNAPSHOT + org.gradle.jvmargs=-Xmx1G diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle index ba7a34f31..b81612b0c 100644 --- a/worldedit-bukkit/build.gradle +++ b/worldedit-bukkit/build.gradle @@ -1,3 +1,5 @@ +PlatformConfigKt.applyPlatformAndCoreConfiguration(project) +PlatformConfigKt.applyShadowConfiguration(project) apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'maven' diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index 41efbff01..a5b3bba63 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -6,6 +6,8 @@ plugins { id("net.ltgt.apt-idea") } +PlatformConfigKt.applyPlatformAndCoreConfiguration(project) + configurations.all { Configuration it -> it.resolutionStrategy { ResolutionStrategy rs -> rs.force("com.google.guava:guava:21.0") diff --git a/worldedit-fabric/build.gradle b/worldedit-fabric/build.gradle index 6eee60e9e..70acc7a1d 100644 --- a/worldedit-fabric/build.gradle +++ b/worldedit-fabric/build.gradle @@ -19,6 +19,9 @@ buildscript { } } +PlatformConfigKt.applyPlatformAndCoreConfiguration(project) +PlatformConfigKt.applyShadowConfiguration(project) + apply plugin: 'eclipse' apply plugin: 'fabric-loom' diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle index 0c389e66f..fc3dcaee8 100644 --- a/worldedit-forge/build.gradle +++ b/worldedit-forge/build.gradle @@ -1,15 +1,5 @@ -buildscript { - repositories { - mavenLocal() - mavenCentral() - maven { url = "https://files.minecraftforge.net/maven" } - jcenter() - } - - dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true - } -} +PlatformConfigKt.applyPlatformAndCoreConfiguration(project) +PlatformConfigKt.applyShadowConfiguration(project) apply plugin: 'eclipse' apply plugin: 'net.minecraftforge.gradle' diff --git a/worldedit-libs/README.md b/worldedit-libs/README.md new file mode 100644 index 000000000..6387fde12 --- /dev/null +++ b/worldedit-libs/README.md @@ -0,0 +1,9 @@ +This project shades _API_ libraries, i.e. those libraries +whose classes are publicly referenced from `-core` classes. + +This project _does not_ shade implementation libraries, i.e. +those libraries whose classes are internally depended on. + +This is because the main reason for shading those libraries is for +their internal usage in each platform, not because we need them available to +dependents of `-core` to compile and work with WorldEdit's API. diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle index cc3c681a0..29c096e2d 100644 --- a/worldedit-libs/build.gradle +++ b/worldedit-libs/build.gradle @@ -1,148 +1,3 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -/* - -This project shades API libraries, i.e. those libraries -whose classes are publicly referenced from `-core` classes. - -This project does not shade implementation libraries, i.e. -those libraries whose classes are internally depended on. - -This is because the main reason for shading those libraries is for -their internal usage in each platform, not because we need them available to -dependents of `-core` to compile and work with WorldEdit's API. - - */ -configure(subprojects + project("core:ap")) { - apply plugin: 'java-base' - apply plugin: 'maven' - apply plugin: 'com.github.johnrengelman.shadow' - apply plugin: 'com.jfrog.artifactory' - configurations { - create("shade") - getByName("archives").extendsFrom(getByName("default")) - } - - group = rootProject.group + ".worldedit-libs" - - tasks.register("jar", ShadowJar) { - configurations = [project.configurations.shade] - classifier = "" - - dependencies { - exclude(dependency("com.google.guava:guava")) - exclude(dependency("com.google.code.gson:gson")) - exclude(dependency("org.checkerframework:checker-qual")) - } - - relocate('net.kyori.text', 'com.sk89q.worldedit.util.formatting.text') - } - def altConfigFiles = { String artifactType -> - def deps = configurations.shade.incoming.dependencies - .collect { it.copy() } - .collect { dependency -> - dependency.artifact { artifact -> - artifact.name = dependency.name - artifact.type = artifactType - artifact.extension = 'jar' - artifact.classifier = artifactType - } - dependency - } - - return files(configurations.detachedConfiguration(deps as Dependency[]) - .resolvedConfiguration.lenientConfiguration.getArtifacts() - .findAll { it.classifier == artifactType } - .collect { zipTree(it.file) }) - } - tasks.register("sourcesJar", Jar) { - from { - altConfigFiles('sources') - } - def filePattern = ~'(.*)net/kyori/text((?:/|$).*)' - def textPattern = ~/net\.kyori\.text/ - eachFile { - it.filter { String line -> - line.replaceFirst(textPattern, 'com.sk89q.worldedit.util.formatting.text') - } - it.path = it.path.replaceFirst(filePattern, '$1com/sk89q/worldedit/util/formatting/text$2') - } - classifier = "sources" - } - - artifacts { - add("default", jar) { - builtBy(jar) - } - add("archives", sourcesJar) { - builtBy(sourcesJar) - } - } - - tasks.register("install", Upload) { - configuration = configurations.archives - repositories.mavenInstaller { - pom.version = project.version - pom.artifactId = project.name - } - } - - artifactoryPublish { - publishConfigs('default') - } - - build.dependsOn(jar, sourcesJar) -} - -def textExtrasVersion = "3.0.2" -project("core") { - def textVersion = "3.0.1" - def pistonVersion = '0.4.2' - - dependencies { - shade "net.kyori:text-api:$textVersion" - shade "net.kyori:text-serializer-gson:$textVersion" - shade "net.kyori:text-serializer-legacy:$textVersion" - shade "net.kyori:text-serializer-plain:$textVersion" - shade('com.sk89q:jchronic:0.2.4a') { - exclude(group: "junit", module: "junit") - } - shade 'com.thoughtworks.paranamer:paranamer:2.6' - shade 'com.sk89q.lib:jlibnoise:1.0.0' - shade "org.enginehub.piston:core:$pistonVersion" - shade "org.enginehub.piston.core-ap:runtime:$pistonVersion" - shade "org.enginehub.piston:default-impl:$pistonVersion" - } - - project("ap") { - dependencies { - shade "org.enginehub.piston.core-ap:annotations:$pistonVersion" - shade "org.enginehub.piston.core-ap:processor:$pistonVersion" - } - } -} -project("bukkit") { - repositories { - maven { - name = "SpigotMC" - url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" - } - } - dependencies { - shade "net.kyori:text-adapter-bukkit:$textExtrasVersion" - } -} -project("sponge") { - repositories { - maven { - name = "Sponge" - url = "https://repo.spongepowered.org/maven" - } - } - dependencies { - shade "net.kyori:text-adapter-spongeapi:$textExtrasVersion" - } -} - tasks.register("build") { dependsOn(subprojects.collect { it.tasks.named("build") }) } diff --git a/worldedit-libs/bukkit/build.gradle.kts b/worldedit-libs/bukkit/build.gradle.kts new file mode 100644 index 000000000..79734ff82 --- /dev/null +++ b/worldedit-libs/bukkit/build.gradle.kts @@ -0,0 +1,11 @@ +applyLibrariesConfiguration() + +repositories { + maven { + name = "SpigotMC" + url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") + } +} +dependencies { + "shade"("net.kyori:text-adapter-bukkit:${Versions.TEXT_EXTRAS}") +} \ No newline at end of file diff --git a/worldedit-libs/core/ap/build.gradle.kts b/worldedit-libs/core/ap/build.gradle.kts new file mode 100644 index 000000000..44374359b --- /dev/null +++ b/worldedit-libs/core/ap/build.gradle.kts @@ -0,0 +1,6 @@ +applyLibrariesConfiguration() + +dependencies { + "shade"("org.enginehub.piston.core-ap:annotations:${Versions.PISTON}") + "shade"("org.enginehub.piston.core-ap:processor:${Versions.PISTON}") +} diff --git a/worldedit-libs/core/build.gradle.kts b/worldedit-libs/core/build.gradle.kts new file mode 100644 index 000000000..d669216d6 --- /dev/null +++ b/worldedit-libs/core/build.gradle.kts @@ -0,0 +1,16 @@ +applyLibrariesConfiguration() + +dependencies { + "shade"("net.kyori:text-api:${Versions.TEXT}") + "shade"("net.kyori:text-serializer-gson:${Versions.TEXT}") + "shade"("net.kyori:text-serializer-legacy:${Versions.TEXT}") + "shade"("net.kyori:text-serializer-plain:${Versions.TEXT}") + "shade"("com.sk89q:jchronic:0.2.4a") { + exclude(group = "junit", module = "junit") + } + "shade"("com.thoughtworks.paranamer:paranamer:2.6") + "shade"("com.sk89q.lib:jlibnoise:1.0.0") + "shade"("org.enginehub.piston:core:${Versions.PISTON}") + "shade"("org.enginehub.piston.core-ap:runtime:${Versions.PISTON}") + "shade"("org.enginehub.piston:default-impl:${Versions.PISTON}") +} diff --git a/worldedit-libs/fabric/build.gradle.kts b/worldedit-libs/fabric/build.gradle.kts new file mode 100644 index 000000000..388618cea --- /dev/null +++ b/worldedit-libs/fabric/build.gradle.kts @@ -0,0 +1 @@ +applyLibrariesConfiguration() diff --git a/worldedit-libs/forge/build.gradle.kts b/worldedit-libs/forge/build.gradle.kts new file mode 100644 index 000000000..388618cea --- /dev/null +++ b/worldedit-libs/forge/build.gradle.kts @@ -0,0 +1 @@ +applyLibrariesConfiguration() diff --git a/worldedit-libs/sponge/build.gradle.kts b/worldedit-libs/sponge/build.gradle.kts new file mode 100644 index 000000000..5854dd616 --- /dev/null +++ b/worldedit-libs/sponge/build.gradle.kts @@ -0,0 +1,11 @@ +applyLibrariesConfiguration() + +repositories { + maven { + name = "Sponge" + url = uri("https://repo.spongepowered.org/maven") + } +} +dependencies { + "shade"("net.kyori:text-adapter-spongeapi:${Versions.TEXT_EXTRAS}") +} \ No newline at end of file diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle index 8d6633de2..81d445a5d 100644 --- a/worldedit-sponge/build.gradle +++ b/worldedit-sponge/build.gradle @@ -2,6 +2,9 @@ plugins { id("org.spongepowered.plugin") } +PlatformConfigKt.applyPlatformAndCoreConfiguration(project) +PlatformConfigKt.applyShadowConfiguration(project) + repositories { maven { url "https://repo.codemc.org/repository/maven-public" } } From ab8397e517eeab1e34f37b38772cc5b50a5ad871 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 16:45:12 -0700 Subject: [PATCH 254/366] Migrate Bukkit to Kotlin DSL --- buildSrc/src/main/kotlin/PlatformConfig.kt | 2 + worldedit-bukkit/build.gradle | 65 -------------------- worldedit-bukkit/build.gradle.kts | 69 ++++++++++++++++++++++ 3 files changed, 71 insertions(+), 65 deletions(-) delete mode 100644 worldedit-bukkit/build.gradle create mode 100644 worldedit-bukkit/build.gradle.kts diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index 85042cc9f..faf7a785a 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -20,6 +20,8 @@ import org.gradle.kotlin.dsl.named fun Project.applyPlatformAndCoreConfiguration() { applyCommonConfiguration() apply(plugin = "java") + apply(plugin = "eclipse") + apply(plugin = "idea") apply(plugin = "maven") apply(plugin = "checkstyle") apply(plugin = "com.github.johnrengelman.shadow") diff --git a/worldedit-bukkit/build.gradle b/worldedit-bukkit/build.gradle deleted file mode 100644 index b81612b0c..000000000 --- a/worldedit-bukkit/build.gradle +++ /dev/null @@ -1,65 +0,0 @@ -PlatformConfigKt.applyPlatformAndCoreConfiguration(project) -PlatformConfigKt.applyShadowConfiguration(project) -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'maven' -apply plugin: 'java-library' - -repositories { - maven { url "https://hub.spigotmc.org/nexus/content/groups/public" } - maven { url "https://repo.codemc.org/repository/maven-public" } - maven { url "https://papermc.io/repo/repository/maven-public/" } -} - -configurations.all { Configuration it -> - it.resolutionStrategy { ResolutionStrategy rs -> - rs.force("com.google.guava:guava:21.0") - } -} - -dependencies { - api project(':worldedit-core') - api project(':worldedit-libs:bukkit') - api 'org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT' // zzz - compileOnly 'com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT' - implementation 'io.papermc:paperlib:1.0.2' - compileOnly 'com.sk89q:dummypermscompat:1.10' - implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' - implementation 'org.bstats:bstats-bukkit:1.5' - testCompile 'org.mockito:mockito-core:1.9.0-rc1' -} - -processResources { - filesMatching('plugin.yml') { - expand 'internalVersion': project.internalVersion - } - from (zipTree('src/main/resources/worldedit-adapters.jar').matching { - exclude 'META-INF/' - }) - exclude '**/worldedit-adapters.jar' -} - -jar { - manifest { - attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version": version) - } -} - -shadowJar { - dependencies { - relocate "org.slf4j", "com.sk89q.worldedit.slf4j" - relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge" - include(dependency(':worldedit-core')) - include(dependency('org.slf4j:slf4j-api')) - include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) - relocate ("org.bstats", "com.sk89q.worldedit.bukkit.bstats") { - include(dependency("org.bstats:bstats-bukkit:1.5")) - } - relocate ("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") { - include(dependency("io.papermc:paperlib:1.0.2")) - } - } -} - -build.dependsOn(shadowJar) diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts new file mode 100644 index 000000000..ee1b94c27 --- /dev/null +++ b/worldedit-bukkit/build.gradle.kts @@ -0,0 +1,69 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + `java-library` +} + +applyPlatformAndCoreConfiguration() +applyShadowConfiguration() + +repositories { + maven { url = uri("https://hub.spigotmc.org/nexus/content/groups/public") } + maven { url = uri("https://repo.codemc.org/repository/maven-public") } + maven { url = uri("https://papermc.io/repo/repository/maven-public/") } +} + +configurations.all { + resolutionStrategy { + force("com.google.guava:guava:21.0") + } +} + +dependencies { + "api"(project(":worldedit-core")) + "api"(project(":worldedit-libs:bukkit")) + "api"("org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT") + "compileOnly"("com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT") + "implementation"("io.papermc:paperlib:1.0.2") + "compileOnly"("com.sk89q:dummypermscompat:1.10") + "implementation"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1") + "implementation"("org.bstats:bstats-bukkit:1.5") + "testCompile"("org.mockito:mockito-core:1.9.0-rc1") +} + +tasks.named("processResources") { + filesMatching("plugin.yml") { + expand("internalVersion" to project.ext["internalVersion"]) + } + from(zipTree("src/main/resources/worldedit-adapters.jar").matching { + exclude("META-INF/") + }) + exclude("**/worldedit-adapters.jar") +} + +tasks.named("jar") { + manifest { + attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", + "WorldEdit-Version" to project.version) + } +} + +tasks.named("shadowJar") { + dependencies { + relocate("org.slf4j", "com.sk89q.worldedit.slf4j") + relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge") + include(dependency(":worldedit-core")) + include(dependency("org.slf4j:slf4j-api")) + include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + relocate("org.bstats", "com.sk89q.worldedit.bukkit.bstats") { + include(dependency("org.bstats:bstats-bukkit:1.5")) + } + relocate("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") { + include(dependency("io.papermc:paperlib:1.0.2")) + } + } +} + +tasks.named("assemble").configure { + dependsOn("shadowJar") +} From 55100761a33c5c0086e06078ed641ed86bf56a78 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 17:07:37 -0700 Subject: [PATCH 255/366] Migrate Core to Kotlin DSL --- buildSrc/src/main/kotlin/Versions.kt | 1 + worldedit-core/build.gradle | 53 ------------------------ worldedit-core/build.gradle.kts | 50 ++++++++++++++++++++++ worldedit-core/doctools/build.gradle.kts | 6 +-- 4 files changed, 53 insertions(+), 57 deletions(-) delete mode 100644 worldedit-core/build.gradle create mode 100644 worldedit-core/build.gradle.kts diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index fd61ee13b..0f79cbfd1 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -2,4 +2,5 @@ object Versions { const val TEXT = "3.0.1" const val TEXT_EXTRAS = "3.0.2" const val PISTON = "0.4.2" + const val AUTO_VALUE = "1.6.5" } diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle deleted file mode 100644 index a5b3bba63..000000000 --- a/worldedit-core/build.gradle +++ /dev/null @@ -1,53 +0,0 @@ -plugins { - id("java-library") - id("eclipse") - id("idea") - id("net.ltgt.apt-eclipse") - id("net.ltgt.apt-idea") -} - -PlatformConfigKt.applyPlatformAndCoreConfiguration(project) - -configurations.all { Configuration it -> - it.resolutionStrategy { ResolutionStrategy rs -> - rs.force("com.google.guava:guava:21.0") - } -} - -dependencies { - compile project(':worldedit-libs:core') - compile 'de.schlichtherle:truezip:6.8.3' - compile 'org.mozilla:rhino:1.7R5' - compile 'org.yaml:snakeyaml:1.9' - compile 'com.google.guava:guava:21.0' - compile 'com.google.code.findbugs:jsr305:1.3.9' - compile 'com.google.code.gson:gson:2.8.0' - compile 'com.googlecode.json-simple:json-simple:1.1.1' - compile 'org.slf4j:slf4j-api:1.7.26' - - compileOnly project(':worldedit-libs:core:ap') - annotationProcessor project(':worldedit-libs:core:ap') - annotationProcessor "com.google.guava:guava:21.0" - def avVersion = "1.6.5" - compileOnly "com.google.auto.value:auto-value-annotations:$avVersion" - annotationProcessor "com.google.auto.value:auto-value:$avVersion" - //compile 'net.sf.trove4j:trove4j:3.0.3' - testCompile 'org.mockito:mockito-core:1.9.0-rc1' -} - -tasks.withType(JavaCompile).configureEach { - dependsOn(":worldedit-libs:build") - it.options.compilerArgs.add("-Aarg.name.key.prefix=") -} - -sourceSets { - main { - java { - srcDir 'src/main/java' - srcDir 'src/legacy/java' - } - resources { - srcDir 'src/main/resources' - } - } -} diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts new file mode 100644 index 000000000..6d268e843 --- /dev/null +++ b/worldedit-core/build.gradle.kts @@ -0,0 +1,50 @@ +plugins { + id("java-library") + id("net.ltgt.apt-eclipse") + id("net.ltgt.apt-idea") +} + +applyPlatformAndCoreConfiguration() + +configurations.all { + resolutionStrategy { + force("com.google.guava:guava:21.0") + } +} + +dependencies { + "compile"(project(":worldedit-libs:core")) + "compile"("de.schlichtherle:truezip:6.8.3") + "compile"("rhino:js:1.7R2") + "compile"("org.yaml:snakeyaml:1.9") + "compile"("com.google.guava:guava:21.0") + "compile"("com.google.code.findbugs:jsr305:1.3.9") + "compile"("com.google.code.gson:gson:2.8.0") + "compile"("com.googlecode.json-simple:json-simple:1.1.1") + "compile"("org.slf4j:slf4j-api:1.7.26") + + "compileOnly"(project(":worldedit-libs:core:ap")) + "annotationProcessor"(project(":worldedit-libs:core:ap")) + // ensure this is on the classpath for the AP + "annotationProcessor"("com.google.guava:guava:21.0") + "compileOnly"("com.google.auto.value:auto-value-annotations:${Versions.AUTO_VALUE}") + "annotationProcessor"("com.google.auto.value:auto-value:${Versions.AUTO_VALUE}") + "testCompile"("org.mockito:mockito-core:1.9.0-rc1") +} + +tasks.withType().configureEach { + dependsOn(":worldedit-libs:build") + options.compilerArgs.add("-Aarg.name.key.prefix=") +} + +sourceSets { + main { + java { + srcDir("src/main/java") + srcDir("src/legacy/java") + } + resources { + srcDir("src/main/resources") + } + } +} diff --git a/worldedit-core/doctools/build.gradle.kts b/worldedit-core/doctools/build.gradle.kts index 75a347ece..803e1078e 100644 --- a/worldedit-core/doctools/build.gradle.kts +++ b/worldedit-core/doctools/build.gradle.kts @@ -4,14 +4,12 @@ plugins { kotlin("jvm") version "1.3.41" } +applyCommonConfiguration() + tasks.withType { kotlinOptions.jvmTarget = "1.8" } -repositories { - jcenter() -} - dependencies { "implementation"(project(":worldedit-libs:core:ap")) "implementation"(project(":worldedit-core")) From 47b9716bdcae6754c44f42702ce4871e45a4f90d Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 17:29:43 -0700 Subject: [PATCH 256/366] Migrate Fabric to Kotlin DSL --- worldedit-fabric/build.gradle | 108 ----------------------------- worldedit-fabric/build.gradle.kts | 109 ++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 108 deletions(-) delete mode 100644 worldedit-fabric/build.gradle create mode 100644 worldedit-fabric/build.gradle.kts diff --git a/worldedit-fabric/build.gradle b/worldedit-fabric/build.gradle deleted file mode 100644 index 70acc7a1d..000000000 --- a/worldedit-fabric/build.gradle +++ /dev/null @@ -1,108 +0,0 @@ -import net.fabricmc.loom.task.RemapJarTask - -buildscript { - repositories { - jcenter() - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - maven { - name = 'sponge' - url = 'https://repo.spongepowered.org/maven' - } - } - - dependencies { - classpath 'net.fabricmc:fabric-loom:0.2.4-SNAPSHOT' - classpath 'org.spongepowered:mixin:0.7.11-SNAPSHOT' - } -} - -PlatformConfigKt.applyPlatformAndCoreConfiguration(project) -PlatformConfigKt.applyShadowConfiguration(project) - -apply plugin: 'eclipse' -apply plugin: 'fabric-loom' - -def minecraftVersion = "1.14.3" -def fabricVersion = "0.3.0+build.187" -def yarnMappings = "1.14.3+build.1" -def loaderVersion = "0.4.8+build.155" - -configurations.all { Configuration it -> - it.resolutionStrategy { ResolutionStrategy rs -> - rs.force("com.google.guava:guava:21.0") - } -} - -dependencies { - compile project(':worldedit-core') - compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1' - - minecraft "com.mojang:minecraft:${minecraftVersion}" - mappings "net.fabricmc:yarn:${yarnMappings}" - modCompile "net.fabricmc:fabric-loader:${loaderVersion}" - - modCompile "net.fabricmc.fabric-api:fabric-api:${fabricVersion}" - - testCompile group: 'org.mockito', name: 'mockito-core', version: '1.9.0-rc1' -} - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -minecraft { -} - -project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}" - -processResources { - // this will ensure that this task is redone when the versions change. - inputs.property 'version', project.internalVersion - - from(sourceSets.main.resources.srcDirs) { - include "fabric.mod.json" - expand "version": project.internalVersion - } - - // copy everything else except the mod json - from(sourceSets.main.resources.srcDirs) { - exclude "fabric.mod.json" - } -} - -jar { - manifest { - attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version": version) - } -} - -shadowJar { - archiveClassifier.set("dist-dev") - dependencies { - relocate "org.slf4j", "com.sk89q.worldedit.slf4j" - relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge" - - include(dependency('org.slf4j:slf4j-api')) - include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) - } -} - -task deobfJar(type: Jar) { - from sourceSets.main.output - archiveClassifier.set("dev") -} - -artifacts { - archives deobfJar -} - -task shadowJarRemap(type: RemapJarTask) { - input shadowJar.archiveFile - output new File(shadowJar.archiveFile.get().asFile.getAbsolutePath().replaceFirst('-dev\\.jar$', ".jar")) -} - -shadowJarRemap.dependsOn(shadowJar) -build.dependsOn(shadowJarRemap) \ No newline at end of file diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts new file mode 100644 index 000000000..f6417686a --- /dev/null +++ b/worldedit-fabric/build.gradle.kts @@ -0,0 +1,109 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import net.fabricmc.loom.task.RemapJarTask + +buildscript { + repositories { + jcenter() + maven { + name = "Fabric" + url = uri("https://maven.fabricmc.net/") + } + maven { + name = "sponge" + url = uri("https://repo.spongepowered.org/maven") + } + } + + dependencies { + "classpath"("net.fabricmc:fabric-loom:0.2.4-SNAPSHOT") + "classpath"("org.spongepowered:mixin:0.7.11-SNAPSHOT") + } +} + +applyPlatformAndCoreConfiguration() +applyShadowConfiguration() + +apply(plugin = "fabric-loom") + +val minecraftVersion = "1.14.3" +val fabricVersion = "0.3.0+build.187" +val yarnMappings = "1.14.3+build.1" +val loaderVersion = "0.4.8+build.155" + +configurations.all { + resolutionStrategy { + force("com.google.guava:guava:21.0") + } +} + +dependencies { + "compile"(project(":worldedit-core")) + "compile"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1") + + "minecraft"("com.mojang:minecraft:$minecraftVersion") + "mappings"("net.fabricmc:yarn:$yarnMappings") + "modCompile"("net.fabricmc:fabric-loader:$loaderVersion") + + "modCompile"("net.fabricmc.fabric-api:fabric-api:$fabricVersion") + + "testCompile"("org.mockito:mockito-core:1.9.0-rc1") +} + +configure { + archivesBaseName = "$archivesBaseName-mc$minecraftVersion" +} + +val sourceSets = project.the().sourceSets + +tasks.named("processResources") { + // this will ensure that this task is redone when the versions change. + inputs.property("version", project.ext["internalVersion"]) + + from(sourceSets["main"].resources.srcDirs) { + include("fabric.mod.json") + expand("version" to project.ext["internalVersion"]) + } + + // copy everything else except the mod json + from(sourceSets["main"].resources.srcDirs) { + exclude("fabric.mod.json") + } +} + +tasks.named("jar") { + manifest { + attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", + "WorldEdit-Version" to project.version) + } +} + +tasks.named("shadowJar") { + archiveClassifier.set("dist-dev") + dependencies { + relocate("org.slf4j", "com.sk89q.worldedit.slf4j") + relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge") + + include(dependency("org.slf4j:slf4j-api")) + include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + } +} + +tasks.register("deobfJar") { + from(sourceSets["main"].output) + archiveClassifier.set("dev") +} + +artifacts { + add("archives", tasks.named("deobfJar")) +} + +tasks.register("remapShadowJar") { + val shadowJar = tasks.getByName("shadowJar") + dependsOn(shadowJar) + setInput(shadowJar.archiveFile) + setOutput(shadowJar.archiveFile.get().asFile.getAbsolutePath().replaceFirst("-dev\\.jar$", ".jar")) +} + +tasks.named("assemble").configure { + dependsOn("remapShadowJar") +} From 3d4025c75738731c7ac1b8c51f0e1dd9be38f663 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 17:45:33 -0700 Subject: [PATCH 257/366] Migrate Forge to Kotlin DSL --- buildSrc/src/main/kotlin/GradleExtras.kt | 6 ++ buildSrc/src/main/kotlin/PlatformConfig.kt | 8 +- worldedit-fabric/build.gradle.kts | 2 - worldedit-forge/build.gradle | 106 -------------------- worldedit-forge/build.gradle.kts | 110 +++++++++++++++++++++ 5 files changed, 119 insertions(+), 113 deletions(-) delete mode 100644 worldedit-forge/build.gradle create mode 100644 worldedit-forge/build.gradle.kts diff --git a/buildSrc/src/main/kotlin/GradleExtras.kt b/buildSrc/src/main/kotlin/GradleExtras.kt index 5358f6b37..e7d1e0ede 100644 --- a/buildSrc/src/main/kotlin/GradleExtras.kt +++ b/buildSrc/src/main/kotlin/GradleExtras.kt @@ -1,6 +1,12 @@ import org.gradle.api.Project import org.gradle.api.plugins.ExtraPropertiesExtension +import org.gradle.api.plugins.JavaPluginConvention +import org.gradle.api.tasks.SourceSetContainer import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.the val Project.ext: ExtraPropertiesExtension get() = extensions.getByType() + +val Project.sourceSets: SourceSetContainer + get() = the().sourceSets diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index faf7a785a..c57dbdd20 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -11,11 +11,9 @@ import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.getByName -import org.gradle.kotlin.dsl.getPlugin -import org.gradle.kotlin.dsl.register -import org.gradle.kotlin.dsl.the -import org.gradle.kotlin.dsl.withType import org.gradle.kotlin.dsl.named +import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.withType fun Project.applyPlatformAndCoreConfiguration() { applyCommonConfiguration() @@ -64,7 +62,7 @@ fun Project.applyPlatformAndCoreConfiguration() { tasks.register("sourcesJar") { dependsOn("classes") archiveClassifier.set("sources") - from(project.the().sourceSets["main"].allSource) + from(sourceSets["main"].allSource) } artifacts { diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index f6417686a..acaa4fb25 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -53,8 +53,6 @@ configure { archivesBaseName = "$archivesBaseName-mc$minecraftVersion" } -val sourceSets = project.the().sourceSets - tasks.named("processResources") { // this will ensure that this task is redone when the versions change. inputs.property("version", project.ext["internalVersion"]) diff --git a/worldedit-forge/build.gradle b/worldedit-forge/build.gradle deleted file mode 100644 index fc3dcaee8..000000000 --- a/worldedit-forge/build.gradle +++ /dev/null @@ -1,106 +0,0 @@ -PlatformConfigKt.applyPlatformAndCoreConfiguration(project) -PlatformConfigKt.applyShadowConfiguration(project) - -apply plugin: 'eclipse' -apply plugin: 'net.minecraftforge.gradle' - -def minecraftVersion = "1.14.3" -def forgeVersion = "27.0.13" - -configurations.all { Configuration it -> - it.resolutionStrategy { ResolutionStrategy rs -> - rs.force("com.google.guava:guava:21.0") - } -} - -dependencies { - compile project(':worldedit-core') - compile 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.2' - - minecraft "net.minecraftforge:forge:${minecraftVersion}-${forgeVersion}" - - testCompile group: 'org.mockito', name: 'mockito-core', version: '1.9.0-rc1' -} - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -minecraft { - mappings channel: 'snapshot', version: "20190626-${minecraftVersion}" - - runs { - client = { - // recommended logging data for a userdev environment - properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP' - // recommended logging level for the console - properties 'forge.logging.console.level': 'debug' - workingDirectory project.file('run').canonicalPath - source sourceSets.main - } - server = { - // recommended logging data for a userdev environment - properties 'forge.logging.markers': 'SCAN,REGISTRIES,REGISTRYDUMP' - // recommended logging level for the console - properties 'forge.logging.console.level': 'debug' - workingDirectory project.file('run').canonicalPath - source sourceSets.main - } - } - -} - -project.archivesBaseName = "${project.archivesBaseName}-mc${minecraftVersion}" - -processResources { - // this will ensure that this task is redone when the versions change. - inputs.property 'version', project.internalVersion - inputs.property 'forgeVersion', forgeVersion - - // replace stuff in mcmod.info, nothing else - from(sourceSets.main.resources.srcDirs) { - include 'META-INF/mods.toml' - - // replace version and mcversion - expand 'version': project.internalVersion, 'forgeVersion': forgeVersion - } - - // copy everything else except the mcmod.info - from(sourceSets.main.resources.srcDirs) { - exclude 'META-INF/mods.toml' - } -} - -jar { - manifest { - attributes("WorldEdit-Version": version) - } -} - -shadowJar { - dependencies { - relocate "org.slf4j", "com.sk89q.worldedit.slf4j" - relocate "org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge" - - include(dependency('org.slf4j:slf4j-api')) - include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) - include(dependency("de.schlichtherle:truezip")) - include(dependency("org.mozilla:rhino")) - } -} - -afterEvaluate { - reobf { - shadowJar { - mappings = createMcpToSrg.output - } - } -} - -task deobfJar(type: Jar) { - from sourceSets.main.output - getArchiveClassifier().set("dev") -} - -artifacts { - archives deobfJar -} diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts new file mode 100644 index 000000000..25e159344 --- /dev/null +++ b/worldedit-forge/build.gradle.kts @@ -0,0 +1,110 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import net.minecraftforge.gradle.common.util.RunConfig +import net.minecraftforge.gradle.userdev.UserDevExtension +import net.minecraftforge.gradle.userdev.tasks.GenerateSRG +import net.minecraftforge.gradle.userdev.tasks.RenameJarInPlace + +plugins { + id("net.minecraftforge.gradle") +} + +applyPlatformAndCoreConfiguration() +applyShadowConfiguration() + +val minecraftVersion = "1.14.3" +val forgeVersion = "27.0.13" + +configurations.all { + resolutionStrategy { + force("com.google.guava:guava:21.0") + } +} + +dependencies { + "compile"(project(":worldedit-core")) + "compile"("org.apache.logging.log4j:log4j-slf4j-impl:2.11.2") + + "minecraft"("net.minecraftforge:forge:$minecraftVersion-$forgeVersion") + + "testCompile"("org.mockito:mockito-core:1.9.0-rc1") +} + +configure { + mappings(mapOf( + "channel" to "snapshot", + "version" to "20190626-$minecraftVersion" + )) + + runs { + val runConfig = Action { + properties(mapOf( + "forge.logging.markers" to "SCAN,REGISTRIES,REGISTRYDUMP", + "forge.logging.console.level" to "debug" + )) + workingDirectory = project.file("run").canonicalPath + source(sourceSets["main"]) + } + create("client", runConfig) + create("server", runConfig) + } + +} + +configure { + archivesBaseName = "$archivesBaseName-mc$minecraftVersion" +} + +tasks.named("processResources") { + // this will ensure that this task is redone when the versions change. + inputs.property("version", project.ext["internalVersion"]) + inputs.property("forgeVersion", forgeVersion) + + // replace stuff in mcmod.info, nothing else + from(sourceSets["main"].resources.srcDirs) { + include("META-INF/mods.toml") + + // replace version and mcversion + expand( + "version" to project.ext["internalVersion"], + "forgeVersion" to forgeVersion + ) + } + + // copy everything else except the mcmod.info + from(sourceSets["main"].resources.srcDirs) { + exclude("META-INF/mods.toml") + } +} + +tasks.named("jar") { + manifest { + attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", + "WorldEdit-Version" to project.version) + } +} + +tasks.named("shadowJar") { + dependencies { + relocate("org.slf4j", "com.sk89q.worldedit.slf4j") + relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge") + + include(dependency("org.slf4j:slf4j-api")) + include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + } +} + +afterEvaluate { + val reobf = extensions.getByName>("reobf") + reobf.maybeCreate("shadowJar").run { + mappings = tasks.getByName("createMcpToSrg").output + } +} + +tasks.register("deobfJar") { + from(sourceSets["main"].output) + archiveClassifier.set("dev") +} + +artifacts { + add("archives", tasks.named("deobfJar")) +} From 3bdc1c1cf2e838b9d8d074970d715c052a6f2699 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 17:48:31 -0700 Subject: [PATCH 258/366] Fixup after shade rhino merge --- worldedit-core/build.gradle.kts | 2 +- worldedit-forge/build.gradle.kts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index 6d268e843..939679383 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -15,7 +15,7 @@ configurations.all { dependencies { "compile"(project(":worldedit-libs:core")) "compile"("de.schlichtherle:truezip:6.8.3") - "compile"("rhino:js:1.7R2") + "compile"("org.mozilla:rhino:1.7R5") "compile"("org.yaml:snakeyaml:1.9") "compile"("com.google.guava:guava:21.0") "compile"("com.google.code.findbugs:jsr305:1.3.9") diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index 25e159344..76abc2ac7 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -90,6 +90,9 @@ tasks.named("shadowJar") { include(dependency("org.slf4j:slf4j-api")) include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + include(dependency("de.schlichtherle:truezip")) + include(dependency("org.mozilla:rhino")) + } } From 5a14693aa95f24026a68e69350032f59f73008fd Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 17:59:23 -0700 Subject: [PATCH 259/366] Migrate Sponge, Libs to Kotlin DSL --- worldedit-forge/build.gradle.kts | 3 +- worldedit-libs/build.gradle | 3 -- worldedit-libs/build.gradle.kts | 3 ++ worldedit-sponge/build.gradle | 52 ------------------------------ worldedit-sponge/build.gradle.kts | 53 +++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 57 deletions(-) delete mode 100644 worldedit-libs/build.gradle create mode 100644 worldedit-libs/build.gradle.kts delete mode 100644 worldedit-sponge/build.gradle create mode 100644 worldedit-sponge/build.gradle.kts diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index 76abc2ac7..78c23c898 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -78,8 +78,7 @@ tasks.named("processResources") { tasks.named("jar") { manifest { - attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version" to project.version) + attributes("WorldEdit-Version" to project.version) } } diff --git a/worldedit-libs/build.gradle b/worldedit-libs/build.gradle deleted file mode 100644 index 29c096e2d..000000000 --- a/worldedit-libs/build.gradle +++ /dev/null @@ -1,3 +0,0 @@ -tasks.register("build") { - dependsOn(subprojects.collect { it.tasks.named("build") }) -} diff --git a/worldedit-libs/build.gradle.kts b/worldedit-libs/build.gradle.kts new file mode 100644 index 000000000..40b3746a9 --- /dev/null +++ b/worldedit-libs/build.gradle.kts @@ -0,0 +1,3 @@ +tasks.register("build") { + dependsOn(subprojects.map { it.tasks.named("build") }) +} diff --git a/worldedit-sponge/build.gradle b/worldedit-sponge/build.gradle deleted file mode 100644 index 81d445a5d..000000000 --- a/worldedit-sponge/build.gradle +++ /dev/null @@ -1,52 +0,0 @@ -plugins { - id("org.spongepowered.plugin") -} - -PlatformConfigKt.applyPlatformAndCoreConfiguration(project) -PlatformConfigKt.applyShadowConfiguration(project) - -repositories { - maven { url "https://repo.codemc.org/repository/maven-public" } -} - -dependencies { - compile project(':worldedit-core') - compile project(':worldedit-libs:sponge') - compile 'org.spongepowered:spongeapi:7.1.0' - compile 'org.bstats:bstats-sponge:1.5' - testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1' -} - -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 - -sponge { - plugin { - id = 'worldedit' - } -} - -jar { - manifest { - attributes("Class-Path": "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", - "WorldEdit-Version": version) - } -} - -shadowJar { - dependencies { - relocate ("org.bstats", "com.sk89q.worldedit.sponge.bstats") { - include(dependency('org.bstats:bstats-sponge:1.5')) - } - } -} - -if (project.hasProperty("signing")) { - apply plugin: 'signing' - - signing { - sign shadowJar - } - - build.dependsOn('signShadowJar') -} \ No newline at end of file diff --git a/worldedit-sponge/build.gradle.kts b/worldedit-sponge/build.gradle.kts new file mode 100644 index 000000000..1c5fa9453 --- /dev/null +++ b/worldedit-sponge/build.gradle.kts @@ -0,0 +1,53 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + id("org.spongepowered.plugin") +} + +applyPlatformAndCoreConfiguration() +applyShadowConfiguration() + +repositories { + maven { url = uri("https://repo.codemc.org/repository/maven-public") } +} + +dependencies { + compile(project(":worldedit-core")) + compile(project(":worldedit-libs:sponge")) + compile("org.spongepowered:spongeapi:7.1.0") + compile("org.bstats:bstats-sponge:1.5") + testCompile("org.mockito:mockito-core:1.9.0-rc1") +} + +sponge { + plugin { + id = "worldedit" + } +} + +tasks.named("jar") { + manifest { + attributes("Class-Path" to "truezip.jar WorldEdit/truezip.jar js.jar WorldEdit/js.jar", + "WorldEdit-Version" to project.version) + } +} + +tasks.named("shadowJar") { + dependencies { + relocate ("org.bstats", "com.sk89q.worldedit.sponge.bstats") { + include(dependency("org.bstats:bstats-sponge:1.5")) + } + } +} + +if (project.hasProperty("signing")) { + apply(plugin = "signing") + + configure { + sign("shadowJar") + } + + tasks.named("build").configure { + dependsOn("signShadowJar") + } +} \ No newline at end of file From 5277f99bf28d57ada505dedfb1c425948bcc1c84 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 10 Jul 2019 18:55:09 -0700 Subject: [PATCH 260/366] Minor fixes for craftscripts in Forge --- worldedit-core/build.gradle.kts | 2 +- .../MinecraftHidingClassShutter.java | 41 +++++ .../scripting/RhinoCraftScriptEngine.java | 1 + .../scripting/java/RhinoScriptEngine.java | 134 --------------- .../java/RhinoScriptEngineFactory.java | 153 ------------------ worldedit-forge/build.gradle.kts | 4 +- 6 files changed, 46 insertions(+), 289 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngine.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngineFactory.java diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index 939679383..6a9266247 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -15,7 +15,7 @@ configurations.all { dependencies { "compile"(project(":worldedit-libs:core")) "compile"("de.schlichtherle:truezip:6.8.3") - "compile"("org.mozilla:rhino:1.7R5") + "compile"("org.mozilla:rhino:1.7.11") "compile"("org.yaml:snakeyaml:1.9") "compile"("com.google.guava:guava:21.0") "compile"("com.google.code.findbugs:jsr305:1.3.9") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java new file mode 100644 index 000000000..20324ed59 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/MinecraftHidingClassShutter.java @@ -0,0 +1,41 @@ +/* + * 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; + +import org.mozilla.javascript.ClassShutter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Hides Minecraft's obfuscated & de-obfuscated names from scripts. + */ +class MinecraftHidingClassShutter implements ClassShutter { + + private static final Logger LOGGER = LoggerFactory.getLogger(MinecraftHidingClassShutter.class); + + @Override + public boolean visibleToScripts(String fullClassName) { + if (!fullClassName.contains(".")) { + // Default package -- probably Minecraft + return false; + } + return !fullClassName.startsWith("net.minecraft"); + } +} 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 79d51cefb..8cad2670b 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 @@ -50,6 +50,7 @@ public class RhinoCraftScriptEngine implements CraftScriptEngine { throws ScriptException, Throwable { RhinoContextFactory factory = new RhinoContextFactory(timeLimit); Context cx = factory.enterContext(); + cx.setClassShutter(new MinecraftHidingClassShutter()); ScriptableObject scriptable = new ImporterTopLevel(cx); Scriptable scope = cx.initStandardObjects(scriptable); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngine.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngine.java deleted file mode 100644 index afab20c3a..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngine.java +++ /dev/null @@ -1,134 +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 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.java; - -import com.sk89q.worldedit.scripting.RhinoContextFactory; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.ImporterTopLevel; -import org.mozilla.javascript.JavaScriptException; -import org.mozilla.javascript.RhinoException; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; - -import java.io.IOException; -import java.io.Reader; - -import javax.script.AbstractScriptEngine; -import javax.script.Bindings; -import javax.script.ScriptContext; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineFactory; -import javax.script.ScriptException; -import javax.script.SimpleBindings; - -public class RhinoScriptEngine extends AbstractScriptEngine { - private ScriptEngineFactory factory; - private Context cx; - - public RhinoScriptEngine() { - RhinoContextFactory factory = new RhinoContextFactory(3000); - factory.enterContext(); - } - - @Override - public Bindings createBindings() { - return new SimpleBindings(); - } - - @Override - public Object eval(String script, ScriptContext context) - throws ScriptException { - - Scriptable scope = setupScope(cx, context); - - String filename = (filename = (String) get(ScriptEngine.FILENAME)) == null - ? "" : filename; - - try { - return cx.evaluateString(scope, script, filename, 1, null); - } catch (RhinoException e) { - String msg; - int line = (line = e.lineNumber()) == 0 ? -1 : line; - - if (e instanceof JavaScriptException) { - msg = String.valueOf(((JavaScriptException) e).getValue()); - } else { - msg = e.getMessage(); - } - - ScriptException scriptException = - new ScriptException(msg, e.sourceName(), line); - scriptException.initCause(e); - - throw scriptException; - } finally { - Context.exit(); - } - } - - @Override - public Object eval(Reader reader, ScriptContext context) - throws ScriptException { - - Scriptable scope = setupScope(cx, context); - - String filename = (filename = (String) get(ScriptEngine.FILENAME)) == null - ? "" : filename; - - try { - return cx.evaluateReader(scope, reader, filename, 1, null); - } catch (RhinoException e) { - String msg; - int line = (line = e.lineNumber()) == 0 ? -1 : line; - - if (e instanceof JavaScriptException) { - msg = String.valueOf(((JavaScriptException) e).getValue()); - } else { - msg = e.getMessage(); - } - - ScriptException scriptException = - new ScriptException(msg, e.sourceName(), line); - scriptException.initCause(e); - - throw scriptException; - } catch (IOException e) { - throw new ScriptException(e); - } finally { - Context.exit(); - } - } - - @Override - public ScriptEngineFactory getFactory() { - if (factory != null) { - return factory; - } else { - return new RhinoScriptEngineFactory(); - } - } - - private Scriptable setupScope(Context cx, ScriptContext context) { - ScriptableObject scriptable = new ImporterTopLevel(cx); - Scriptable scope = cx.initStandardObjects(scriptable); - //ScriptableObject.putProperty(scope, "argv", Context.javaToJS(args, scope)); - return scope; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngineFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngineFactory.java deleted file mode 100644 index ee312229c..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/scripting/java/RhinoScriptEngineFactory.java +++ /dev/null @@ -1,153 +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 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.java; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.script.ScriptEngine; -import javax.script.ScriptEngineFactory; - -public class RhinoScriptEngineFactory implements ScriptEngineFactory { - private static List names; - private static List mimeTypes; - private static List extensions; - - static { - names = new ArrayList<>(5); - names.add("ECMAScript"); - names.add("ecmascript"); - names.add("JavaScript"); - names.add("javascript"); - names.add("js"); - names = Collections.unmodifiableList(names); - - mimeTypes = new ArrayList<>(4); - mimeTypes.add("application/ecmascript"); - mimeTypes.add("text/ecmascript"); - mimeTypes.add("application/javascript"); - mimeTypes.add("text/javascript"); - mimeTypes = Collections.unmodifiableList(mimeTypes); - - extensions = new ArrayList<>(2); - extensions.add("emcascript"); - extensions.add("js"); - extensions = Collections.unmodifiableList(extensions); - } - - @Override - public String getEngineName() { - return "Rhino JavaScript Engine (SK)"; - } - - @Override - public String getEngineVersion() { - return "unknown"; - } - - @Override - public List getExtensions() { - return extensions; - } - - @Override - public String getLanguageName() { - return "EMCAScript"; - } - - @Override - public String getLanguageVersion() { - return "1.8"; - } - - @Override - public String getMethodCallSyntax(String obj, String m, String... args) { - StringBuilder s = new StringBuilder(); - s.append(obj); - s.append("."); - s.append(m); - s.append("("); - - for (int i = 0; i < args.length; ++i) { - s.append(args[i]); - if (i < args.length - 1) { - s.append(","); - } - } - - s.append(")"); - - return s.toString(); - } - - @Override - public List getMimeTypes() { - return mimeTypes; - } - - @Override - public List getNames() { - return names; - } - - @Override - public String getOutputStatement(String str) { - return "print(" + str.replace("\\", "\\\\") - .replace("\"", "\\\\\"") - .replace(";", "\\\\;") + ")"; - } - - @Override - public Object getParameter(String key) { - switch (key) { - case ScriptEngine.ENGINE: - return getEngineName(); - case ScriptEngine.ENGINE_VERSION: - return getEngineVersion(); - case ScriptEngine.NAME: - return getEngineName(); - case ScriptEngine.LANGUAGE: - return getLanguageName(); - case ScriptEngine.LANGUAGE_VERSION: - return getLanguageVersion(); - case "THREADING": - return "MULTITHREADED"; - default: - throw new IllegalArgumentException("Invalid key"); - } - } - - @Override - public String getProgram(String... statements) { - StringBuilder s = new StringBuilder(); - for (String stmt : statements) { - s.append(stmt); - s.append(";"); - } - return s.toString(); - } - - @Override - public ScriptEngine getScriptEngine() { - return new RhinoScriptEngine(); - } - -} diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index 78c23c898..235900181 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -91,7 +91,9 @@ tasks.named("shadowJar") { include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) include(dependency("de.schlichtherle:truezip")) include(dependency("org.mozilla:rhino")) - + } + minimize { + exclude(dependency("org.mozilla:rhino")) } } From 52a62b984ba5ce29c14bd0a90e9fb78ef4db553b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 13 Jul 2019 22:16:16 -0700 Subject: [PATCH 261/366] Improve logging, update to 5.5.1 --- build.gradle.kts | 6 +++--- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 7088d0893..07b943531 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,6 @@ import org.ajoberstar.grgit.Grgit -println(""" +logger.lifecycle(""" ******************************************* You are building WorldEdit! @@ -19,9 +19,9 @@ applyRootArtifactoryConfig() if (!project.hasProperty("gitCommitHash")) { apply(plugin = "org.ajoberstar.grgit") ext["gitCommitHash"] = try { - (ext["grgit"] as Grgit).head().abbreviatedId + (ext["grgit"] as Grgit?)?.head()?.abbreviatedId } catch (e: Exception) { - println("Error getting commit hash: " + e.message) + logger.warn("Error getting commit hash", e) "no_git_id" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e0c4de36d..430dfabc5 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-5.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 58863c22e8d79602f50dc9b667866bdc1e2c1316 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 13 Jul 2019 23:26:31 -0700 Subject: [PATCH 262/366] Try downgrading fabric --- worldedit-fabric/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index acaa4fb25..f0843a651 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -15,7 +15,7 @@ buildscript { } dependencies { - "classpath"("net.fabricmc:fabric-loom:0.2.4-SNAPSHOT") + "classpath"("net.fabricmc:fabric-loom:0.2.3-SNAPSHOT") "classpath"("org.spongepowered:mixin:0.7.11-SNAPSHOT") } } From 98e29f634fc0cf57181b9147ccc1cc59b3d5976c Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 14 Jul 2019 00:00:11 -0700 Subject: [PATCH 263/366] Fix fabric output jar --- worldedit-fabric/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index f0843a651..d41010624 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -99,7 +99,7 @@ tasks.register("remapShadowJar") { val shadowJar = tasks.getByName("shadowJar") dependsOn(shadowJar) setInput(shadowJar.archiveFile) - setOutput(shadowJar.archiveFile.get().asFile.getAbsolutePath().replaceFirst("-dev\\.jar$", ".jar")) + setOutput(shadowJar.archiveFile.get().asFile.absolutePath.replace(Regex("-dev\\.jar$"), ".jar")) } tasks.named("assemble").configure { From ad5dcbea5864f4fbc21ae4e66b378e0341a7a9e5 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Jul 2019 09:14:02 -0700 Subject: [PATCH 264/366] Attempt to fix ASM conflict --- buildSrc/build.gradle.kts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 658143d8d..1d1da51c1 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -15,7 +15,11 @@ repositories { configurations.all { resolutionStrategy { // Fabric needs this. - force("commons-io:commons-io:2.5", "org.ow2.asm:asm:7.1") + force( + "commons-io:commons-io:2.5", + "org.ow2.asm:asm:7.1", + "org.ow2.asm:asm-commons:7.1" + ) } } From 5fa311be48e18f24a67f1bc8a12fd36d3133b8c2 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Jul 2019 09:42:28 -0700 Subject: [PATCH 265/366] Account for IntelliJ bug --- worldedit-fabric/build.gradle.kts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index d41010624..7b11f0aca 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -1,5 +1,6 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import net.fabricmc.loom.task.RemapJarTask +import kotlin.reflect.KClass buildscript { repositories { @@ -95,11 +96,16 @@ artifacts { add("archives", tasks.named("deobfJar")) } -tasks.register("remapShadowJar") { - val shadowJar = tasks.getByName("shadowJar") - dependsOn(shadowJar) - setInput(shadowJar.archiveFile) - setOutput(shadowJar.archiveFile.get().asFile.absolutePath.replace(Regex("-dev\\.jar$"), ".jar")) +// intellij has trouble detecting RemapJarTask as a subclass of Task +@Suppress("UNCHECKED_CAST") +val remapJarIntellijHack = RemapJarTask::class as KClass +tasks.register("remapShadowJar", remapJarIntellijHack) { + (this as RemapJarTask).run { + val shadowJar = tasks.getByName("shadowJar") + dependsOn(shadowJar) + setInput(shadowJar.archiveFile) + setOutput(shadowJar.archiveFile.get().asFile.absolutePath.replace(Regex("-dev\\.jar$"), ".jar")) + } } tasks.named("assemble").configure { From e98b99edcd523e6690a9b5b963fd52b2f310eb9b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Jul 2019 15:25:17 -0700 Subject: [PATCH 266/366] Properly acquire JUnit 4, drop json-simple --- buildSrc/src/main/kotlin/PlatformConfig.kt | 5 +++++ worldedit-core/build.gradle.kts | 1 - .../sk89q/worldedit/util/paste/EngineHubPaste.java | 13 ++++++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index c57dbdd20..e4ab9629a 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -9,6 +9,7 @@ import org.gradle.api.tasks.javadoc.Javadoc import org.gradle.external.javadoc.CoreJavadocOptions import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.getByName import org.gradle.kotlin.dsl.named @@ -38,6 +39,10 @@ fun Project.applyPlatformAndCoreConfiguration() { toolVersion = "7.6.1" } + dependencies { + "testImplementation"("junit:junit:4.12") + } + // Java 8 turns on doclint which we fail tasks.withType().configureEach { (options as CoreJavadocOptions).addStringOption("Xdoclint:none", "-quiet") diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index 6a9266247..274cf2e06 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -20,7 +20,6 @@ dependencies { "compile"("com.google.guava:guava:21.0") "compile"("com.google.code.findbugs:jsr305:1.3.9") "compile"("com.google.code.gson:gson:2.8.0") - "compile"("com.googlecode.json-simple:json-simple:1.1.1") "compile"("org.slf4j:slf4j-api:1.7.26") "compileOnly"(project(":worldedit-libs:core:ap")) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java index ac7484846..ab8ebe029 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java @@ -19,8 +19,9 @@ package com.sk89q.worldedit.util.paste; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import com.sk89q.worldedit.util.net.HttpRequest; -import org.json.simple.JSONValue; import java.io.IOException; import java.net.URL; @@ -33,6 +34,8 @@ public class EngineHubPaste implements Paster { private static final Pattern URL_PATTERN = Pattern.compile("https?://.+$"); + private static final Gson GSON = new Gson(); + @Override public Callable paste(String content) { return new PasteTask(content); @@ -59,10 +62,10 @@ public class EngineHubPaste implements Paster { .returnContent() .asString("UTF-8").trim(); - Object object = JSONValue.parse(result); - if (object instanceof Map) { - @SuppressWarnings("unchecked") - String urlString = String.valueOf(((Map) object).get("url")); + Map object = GSON.fromJson(result, new TypeToken>() { + }.getType()); + if (object != null) { + String urlString = String.valueOf(object.get("url")); Matcher m = URL_PATTERN.matcher(urlString); if (m.matches()) { From 429d022752af0951bb53990907c2130a901cfab1 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Jul 2019 16:07:11 -0700 Subject: [PATCH 267/366] Move Core to JUnit 5 --- buildSrc/src/main/kotlin/PlatformConfig.kt | 8 ++++- buildSrc/src/main/kotlin/Versions.kt | 1 + worldedit-bukkit/build.gradle.kts | 4 ++- .../util/commands/CommandContextTest.java | 25 +++++++------ .../transform/BlockTransformExtentTest.java | 18 +++++----- .../command/CommandArgParserTest.java | 4 +-- .../internal/expression/ExpressionTest.java | 35 +++++++++---------- .../sk89q/worldedit/util/LocationTest.java | 8 ++--- .../worldedit/util/eventbus/EventBusTest.java | 4 +-- 9 files changed, 59 insertions(+), 48 deletions(-) diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index e4ab9629a..c5deea857 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -6,6 +6,7 @@ import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.plugins.quality.CheckstyleExtension import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.javadoc.Javadoc +import org.gradle.api.tasks.testing.Test import org.gradle.external.javadoc.CoreJavadocOptions import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure @@ -39,8 +40,13 @@ fun Project.applyPlatformAndCoreConfiguration() { toolVersion = "7.6.1" } + tasks.withType().configureEach { + useJUnitPlatform() + } + dependencies { - "testImplementation"("junit:junit:4.12") + "testImplementation"("org.junit.jupiter:junit-jupiter-api:${Versions.JUNIT}") + "testRuntime"("org.junit.jupiter:junit-jupiter-engine:${Versions.JUNIT}") } // Java 8 turns on doclint which we fail diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 0f79cbfd1..4679c2d40 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -3,4 +3,5 @@ object Versions { const val TEXT_EXTRAS = "3.0.2" const val PISTON = "0.4.2" const val AUTO_VALUE = "1.6.5" + const val JUNIT = "5.5.0" } diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index ee1b94c27..1343ff2be 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -22,7 +22,9 @@ configurations.all { dependencies { "api"(project(":worldedit-core")) "api"(project(":worldedit-libs:bukkit")) - "api"("org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT") + "api"("org.bukkit:bukkit:1.13.2-R0.1-SNAPSHOT") { + exclude("junit", "junit") + } "compileOnly"("com.destroystokyo.paper:paper-api:1.13.2-R0.1-SNAPSHOT") "implementation"("io.papermc:paperlib:1.0.2") "compileOnly"("com.sk89q:dummypermscompat:1.10") diff --git a/worldedit-core/src/test/java/com/sk89q/minecraft/util/commands/CommandContextTest.java b/worldedit-core/src/test/java/com/sk89q/minecraft/util/commands/CommandContextTest.java index 555c83889..19bd552ec 100644 --- a/worldedit-core/src/test/java/com/sk89q/minecraft/util/commands/CommandContextTest.java +++ b/worldedit-core/src/test/java/com/sk89q/minecraft/util/commands/CommandContextTest.java @@ -19,19 +19,20 @@ package com.sk89q.minecraft.util.commands; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.HashSet; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class CommandContextTest { @@ -39,7 +40,7 @@ public class CommandContextTest { private static final String firstCmdString = "herpderp -opw testers \"mani world\" 'another thing' because something"; CommandContext firstCommand; - @Before + @BeforeEach public void setUpTest() { try { firstCommand = new CommandContext(firstCmdString, new HashSet<>(Arrays.asList('o', 'w'))); @@ -49,10 +50,12 @@ public class CommandContextTest { } } - @Test(expected = CommandException.class) - public void testInvalidFlags() throws CommandException { + @Test + public void testInvalidFlags() { final String failingCommand = "herpderp -opw testers"; - new CommandContext(failingCommand, new HashSet<>(Arrays.asList('o', 'w'))); + assertThrows(CommandException.class, () -> { + new CommandContext(failingCommand, new HashSet<>(Arrays.asList('o', 'w'))); + }); } @Test diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java index 633e359f8..101509aa4 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/extent/transform/BlockTransformExtentTest.java @@ -19,33 +19,33 @@ package com.sk89q.worldedit.extent.transform; -import static org.junit.Assert.assertEquals; - import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import java.util.HashSet; import java.util.Set; -@Ignore("A platform is currently required to get properties, preventing this test.") +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Disabled("A platform is currently required to get properties, preventing this test.") public class BlockTransformExtentTest { private static final Transform ROTATE_90 = new AffineTransform().rotateY(-90); private static final Transform ROTATE_NEG_90 = new AffineTransform().rotateY(90); private final Set ignored = new HashSet<>(); - @Before - public void setUp() throws Exception { + @BeforeEach + public void setUp() { BlockType.REGISTRY.register("worldedit:test", new BlockType("worldedit:test")); } @Test - public void testTransform() throws Exception { + public void testTransform() { for (BlockType type : BlockType.REGISTRY.values()) { if (ignored.contains(type)) { continue; diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java index 7c75de4a6..c696bdabb 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java @@ -21,10 +21,10 @@ package com.sk89q.worldedit.internal.command; import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.internal.util.Substring; -import org.junit.Test; +import org.junit.jupiter.api.Test; import static com.sk89q.worldedit.internal.command.CommandArgParser.spaceSplit; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class CommandArgParserTest { @Test diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java index 28ad67b37..4fe511925 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java @@ -19,16 +19,6 @@ package com.sk89q.worldedit.internal.expression; -import static java.lang.Math.atan2; -import static java.lang.Math.sin; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Platform; @@ -36,9 +26,18 @@ import com.sk89q.worldedit.internal.expression.lexer.LexerException; import com.sk89q.worldedit.internal.expression.parser.ParserException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static java.lang.Math.atan2; +import static java.lang.Math.sin; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class ExpressionTest { - @Before + @BeforeEach public void setup() { Platform mockPlat = Mockito.mock(Platform.class); Mockito.when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() { @@ -51,7 +50,7 @@ public class ExpressionTest { @Test public void testEvaluate() throws ExpressionException { - // check + // check assertEquals(1 - 2 + 3, simpleEval("1 - 2 + 3"), 0); // check unary ops @@ -74,7 +73,7 @@ public class ExpressionTest { compile("#"); fail("Error expected"); } catch (LexerException e) { - assertEquals("Error position", 0, e.getPosition()); + assertEquals(0, e.getPosition(), "Error position"); } // test parser errors @@ -82,13 +81,13 @@ public class ExpressionTest { compile("x"); fail("Error expected"); } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); + assertEquals(0, e.getPosition(), "Error position"); } try { compile("x()"); fail("Error expected"); } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); + assertEquals(0, e.getPosition(), "Error position"); } try { compile("("); @@ -104,19 +103,19 @@ public class ExpressionTest { compile("atan2(1)"); fail("Error expected"); } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); + assertEquals(0, e.getPosition(), "Error position"); } try { compile("atan2(1, 2, 3)"); fail("Error expected"); } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); + assertEquals(0, e.getPosition(), "Error position"); } try { compile("rotate(1, 2, 3)"); fail("Error expected"); } catch (ParserException e) { - assertEquals("Error position", 0, e.getPosition()); + assertEquals(0, e.getPosition(), "Error position"); } } diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/util/LocationTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/util/LocationTest.java index 50dfa649e..2c990ab74 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/util/LocationTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/util/LocationTest.java @@ -19,12 +19,12 @@ package com.sk89q.worldedit.util; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; - import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.world.World; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; /** * Tests {@link Location}. diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java index 6289301dc..82fdb11c0 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/util/eventbus/EventBusTest.java @@ -19,14 +19,14 @@ package com.sk89q.worldedit.util.eventbus; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class EventBusTest { From 3b157b67c3fb56d26ad800fe3da38386c88db276 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Jul 2019 16:10:50 -0700 Subject: [PATCH 268/366] Move Bukkit to JUnit 5 --- .../sk89q/wepif/DinnerPermsResolverTest.java | 30 +++++++++---------- .../worldedit/bukkit/BukkitWorldTest.java | 7 +++-- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/worldedit-bukkit/src/test/java/com/sk89q/wepif/DinnerPermsResolverTest.java b/worldedit-bukkit/src/test/java/com/sk89q/wepif/DinnerPermsResolverTest.java index e207e7b8d..37deab330 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/wepif/DinnerPermsResolverTest.java +++ b/worldedit-bukkit/src/test/java/com/sk89q/wepif/DinnerPermsResolverTest.java @@ -19,26 +19,26 @@ package com.sk89q.wepif; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import org.bukkit.Server; import org.bukkit.plugin.PluginManager; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class DinnerPermsResolverTest { private DinnerPermsResolver resolver; - @Before + @BeforeEach public void setUp() { Server server = mock(Server.class); when(server.getPluginManager()).thenReturn(mock(PluginManager.class)); resolver = new DinnerPermsResolver(server); } - + @Test public void testBasicResolving() { final TestOfflinePermissible permissible = new TestOfflinePermissible(); @@ -49,7 +49,7 @@ public class DinnerPermsResolverTest { assertFalse(resolver.hasPermission(permissible, "completely.unrelated")); permissible.clearPermissions(); } - + @Test public void testBasicWildcardResolution() { final TestOfflinePermissible permissible = new TestOfflinePermissible(); @@ -59,7 +59,7 @@ public class DinnerPermsResolverTest { assertTrue(resolver.hasPermission(permissible, "commandbook.spawnmob.spider.skeleton")); permissible.clearPermissions(); } - + @Test public void testNegatingNodes() { final TestOfflinePermissible permissible = new TestOfflinePermissible(); @@ -67,16 +67,16 @@ public class DinnerPermsResolverTest { permissible.setPermission("commandbook.cuteasianboys", false); permissible.setPermission("commandbook.warp.*", false); permissible.setPermission("commandbook.warp.create", true); - + assertTrue(resolver.hasPermission(permissible, "commandbook.motd")); assertFalse(resolver.hasPermission(permissible, "commandbook.cuteasianboys")); assertFalse(resolver.hasPermission(permissible, "commandbook.warp.remove")); assertTrue(resolver.hasPermission(permissible, "commandbook.warp.create")); - + permissible.clearPermissions(); } - - + + @Test public void testInGroup() { final TestOfflinePermissible permissible = new TestOfflinePermissible(); diff --git a/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java b/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java index e6776cf8c..8851fb926 100644 --- a/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java +++ b/worldedit-bukkit/src/test/java/com/sk89q/worldedit/bukkit/BukkitWorldTest.java @@ -20,15 +20,16 @@ package com.sk89q.worldedit.bukkit; import com.sk89q.worldedit.util.TreeGenerator; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; public class BukkitWorldTest { @Test public void testTreeTypeMapping() { for (TreeGenerator.TreeType type : TreeGenerator.TreeType.values()) { - Assert.assertNotNull("No mapping for: " + type, BukkitWorld.toBukkitTreeType(type)); + assertNotNull(BukkitWorld.toBukkitTreeType(type), "No mapping for: " + type); } } From 5c5c822f4b8fc1ba771a85ed868d49632241a861 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Jul 2019 16:19:28 -0700 Subject: [PATCH 269/366] Replace try-fail-catch-assert with assertThrows --- .../internal/expression/ExpressionTest.java | 105 ++++++++---------- 1 file changed, 47 insertions(+), 58 deletions(-) diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java index 4fe511925..5cbb6e7b2 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java @@ -32,9 +32,10 @@ import org.mockito.Mockito; import static java.lang.Math.atan2; import static java.lang.Math.sin; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; public class ExpressionTest { @BeforeEach @@ -67,56 +68,46 @@ public class ExpressionTest { } @Test - public void testErrors() throws ExpressionException { - // test lexer errors - try { - compile("#"); - fail("Error expected"); - } catch (LexerException e) { - assertEquals(0, e.getPosition(), "Error position"); - } - - // test parser errors - try { - compile("x"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals(0, e.getPosition(), "Error position"); - } - try { - compile("x()"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals(0, e.getPosition(), "Error position"); - } - try { - compile("("); - fail("Error expected"); - } catch (ParserException ignored) {} - try { - compile("x("); - fail("Error expected"); - } catch (ParserException ignored) {} - - // test overloader errors - try { - compile("atan2(1)"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals(0, e.getPosition(), "Error position"); - } - try { - compile("atan2(1, 2, 3)"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals(0, e.getPosition(), "Error position"); - } - try { - compile("rotate(1, 2, 3)"); - fail("Error expected"); - } catch (ParserException e) { - assertEquals(0, e.getPosition(), "Error position"); - } + public void testErrors() { + assertAll( + // test lexer errors + () -> { + LexerException e = assertThrows(LexerException.class, + () -> compile("#")); + assertEquals(0, e.getPosition(), "Error position"); + }, + // test parser errors + () -> { + ParserException e = assertThrows(ParserException.class, + () -> compile("x")); + assertEquals(0, e.getPosition(), "Error position"); + }, + () -> { + ParserException e = assertThrows(ParserException.class, + () -> compile("x()")); + assertEquals(0, e.getPosition(), "Error position"); + }, + () -> assertThrows(ParserException.class, + () -> compile("(")), + () -> assertThrows(ParserException.class, + () -> compile("x(")), + // test overloader errors + () -> { + ParserException e = assertThrows(ParserException.class, + () -> compile("atan2(1)")); + assertEquals(0, e.getPosition(), "Error position"); + }, + () -> { + ParserException e = assertThrows(ParserException.class, + () -> compile("atan2(1, 2, 3)")); + assertEquals(0, e.getPosition(), "Error position"); + }, + () -> { + ParserException e = assertThrows(ParserException.class, + () -> compile("rotate(1, 2, 3)")); + assertEquals(0, e.getPosition(), "Error position"); + } + ); } @Test @@ -180,13 +171,11 @@ public class ExpressionTest { } @Test - public void testTimeout() throws Exception { - try { - simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"); - fail("Loop was not stopped."); - } catch (EvaluationException e) { - assertTrue(e.getMessage().contains("Calculations exceeded time limit")); - } + public void testTimeout() { + EvaluationException e = assertThrows(EvaluationException.class, + () -> simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"), + "Loop was not stopped."); + assertTrue(e.getMessage().contains("Calculations exceeded time limit")); } private double simpleEval(String expressionString) throws ExpressionException { From c1f4eecd774c5fd13f69a8364e473d948986dd9b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 15 Jul 2019 17:18:10 -0700 Subject: [PATCH 270/366] Narrow timeout test exception type --- .../sk89q/worldedit/internal/expression/ExpressionTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java index 5cbb6e7b2..d26d955d0 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.internal.expression.lexer.LexerException; import com.sk89q.worldedit.internal.expression.parser.ParserException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; +import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -172,7 +173,7 @@ public class ExpressionTest { @Test public void testTimeout() { - EvaluationException e = assertThrows(EvaluationException.class, + ExpressionTimeoutException e = assertThrows(ExpressionTimeoutException.class, () -> simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"), "Loop was not stopped."); assertTrue(e.getMessage().contains("Calculations exceeded time limit")); From f75104f2accf733987379d45effb17a63537188d Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 16 Jul 2019 19:45:27 -0400 Subject: [PATCH 271/366] Actually use fixed IDs in MCEdit reader. Fixes WORLDEDIT-3947. --- .../extent/clipboard/io/MCEditSchematicReader.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 bcba783a4..f3180df2d 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 @@ -206,6 +206,8 @@ public class MCEditSchematicReader extends NBTSchematicReader { } if (values.isEmpty()) { t = null; + } else { + t = new CompoundTag(values); } if (fixer != null && t != null) { @@ -378,6 +380,10 @@ public class MCEditSchematicReader extends NBTSchematicReader { return "note_block"; case "Structure": return "structure_block"; + case "Chest": + return "chest"; + case "Sign": + return "sign"; default: return id; } From 05cee0a30b305e1bb2a003c71183992a2296e46f Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 16 Jul 2019 21:43:14 -0400 Subject: [PATCH 272/366] Don't overwrite history during changes. Fixes issues with some changes not being undone. I mean, the sphere algorithm needs to not set blocks 20 times, but other things can trigger this too. Also allow radius 0 sphere via //sphere (because /br sphere allows it). --- .../sk89q/worldedit/command/GenerationCommands.java | 10 +++++----- .../history/changeset/BlockOptimizedHistory.java | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) 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 4ae72b9d7..9fcfd2c37 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 @@ -162,13 +162,13 @@ public class GenerationCommands { final double radiusX, radiusY, radiusZ; switch (radii.size()) { case 1: - radiusX = radiusY = radiusZ = Math.max(1, radii.get(0)); + radiusX = radiusY = radiusZ = Math.max(0, radii.get(0)); break; case 3: - radiusX = Math.max(1, radii.get(0)); - radiusY = Math.max(1, radii.get(1)); - radiusZ = Math.max(1, radii.get(2)); + radiusX = Math.max(0, radii.get(0)); + radiusY = Math.max(0, radii.get(1)); + radiusZ = Math.max(0, radii.get(2)); break; default: @@ -205,7 +205,7 @@ public class GenerationCommands { @Arg(desc = "The density of the forest, between 0 and 100", def = "5") double density) throws WorldEditException { checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); - density = density / 100; + density /= 100; int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); player.print(affected + " trees created."); return affected; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java index 9c9ad2a85..05ac90c78 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/history/changeset/BlockOptimizedHistory.java @@ -55,7 +55,9 @@ public class BlockOptimizedHistory extends ArrayListHistory { if (change instanceof BlockChange) { BlockChange blockChange = (BlockChange) change; BlockVector3 position = blockChange.getPosition(); - previous.add(position, blockChange.getPrevious()); + if (!previous.containsLocation(position)) { + previous.add(position, blockChange.getPrevious()); + } current.add(position, blockChange.getCurrent()); } else { super.add(change); From 1d413cde76e01482409d5dea1d3bb4dc5161bcb2 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Thu, 18 Jul 2019 00:38:59 +1000 Subject: [PATCH 273/366] BrushTool typo --- .../main/java/com/sk89q/worldedit/command/tool/BrushTool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java index 2e324f9ee..e8724208b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BrushTool.java @@ -92,7 +92,7 @@ public class BrushTool implements TraceTool { * @return the mask used to stop block traces */ public @Nullable Mask getTraceMask() { - return mask; + return this.traceMask; } /** From 89753477039e8bec08765c96951c7a81e1d352f2 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 17 Jul 2019 18:02:45 -0700 Subject: [PATCH 274/366] Fix Forge regen, by retaining the world reference. Also close the world. --- .../com/sk89q/worldedit/forge/ForgeWorld.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 6abda18d1..dca8f1c1f 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -96,6 +96,7 @@ import net.minecraft.world.storage.WorldInfo; import javax.annotation.Nullable; import java.io.File; +import java.io.IOException; import java.lang.ref.WeakReference; import java.nio.file.Path; import java.util.Collections; @@ -329,19 +330,22 @@ public class ForgeWorld extends AbstractWorld { MinecraftServer server = originalWorld.getServer(); SaveHandler saveHandler = new SaveHandler(saveFolder, originalWorld.getSaveHandler().getWorldDirectory().getName(), server, server.getDataFixer()); - World freshWorld = new ServerWorld(server, server.getBackgroundExecutor(), saveHandler, originalWorld.getWorldInfo(), - originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener()); + try (World freshWorld = new ServerWorld(server, server.getBackgroundExecutor(), saveHandler, originalWorld.getWorldInfo(), + originalWorld.dimension.getType(), originalWorld.getProfiler(), new NoOpChunkStatusListener())) { - // Pre-gen all the chunks - // We need to also pull one more chunk in every direction - CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16)); - for (BlockVector2 chunk : expandedPreGen.getChunks()) { - freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ()); - } + // Pre-gen all the chunks + // We need to also pull one more chunk in every direction + CuboidRegion expandedPreGen = new CuboidRegion(region.getMinimumPoint().subtract(16, 0, 16), region.getMaximumPoint().add(16, 0, 16)); + for (BlockVector2 chunk : expandedPreGen.getChunks()) { + freshWorld.getChunk(chunk.getBlockX(), chunk.getBlockZ()); + } - ForgeWorld from = new ForgeWorld(freshWorld); - for (BlockVector3 vec : region) { - editSession.setBlock(vec, from.getFullBlock(vec)); + ForgeWorld from = new ForgeWorld(freshWorld); + for (BlockVector3 vec : region) { + editSession.setBlock(vec, from.getFullBlock(vec)); + } + } catch (IOException e) { + throw new RuntimeException(e); } } catch (MaxChangedBlocksException e) { throw new RuntimeException(e); From 7b9075c0bfabaf8b9a36efb97cbcb334c0b203ef Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Fri, 19 Jul 2019 21:44:13 +1000 Subject: [PATCH 275/366] Update Fabric to 1.14.4 and fix physics updates --- worldedit-fabric/build.gradle.kts | 6 +++--- .../java/com/sk89q/worldedit/fabric/FabricWorld.java | 9 ++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index 7b11f0aca..f8cb056eb 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -26,9 +26,9 @@ applyShadowConfiguration() apply(plugin = "fabric-loom") -val minecraftVersion = "1.14.3" -val fabricVersion = "0.3.0+build.187" -val yarnMappings = "1.14.3+build.1" +val minecraftVersion = "1.14.4" +val fabricVersion = "0.3.0+build.200" +val yarnMappings = "1.14.4+build.1" val loaderVersion = "0.4.8+build.155" configurations.all { diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java index 8125fb0cb..afc6cc99e 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java @@ -211,7 +211,12 @@ public class FabricWorld extends AbstractWorld { if (successful && notifyAndLight) { world.getChunkManager().getLightingProvider().enqueueLightUpdate(pos); + world.scheduleBlockRender(pos, old, newState); world.updateListeners(pos, old, newState, UPDATE | NOTIFY); + world.updateNeighbors(pos, newState.getBlock()); + if (old.hasComparatorOutput()) { + world.updateHorizontalAdjacent(pos, newState.getBlock()); + } } return successful; @@ -220,7 +225,9 @@ public class FabricWorld extends AbstractWorld { @Override public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { BlockPos pos = new BlockPos(position.getX(), position.getY(), position.getZ()); - getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), getWorld().getBlockState(pos), 1 | 2); + net.minecraft.block.BlockState state = getWorld().getBlockState(pos); + getWorld().updateListeners(pos, FabricAdapter.adapt(previousType), state, 1 | 2); + getWorld().updateNeighbors(pos, state.getBlock()); return true; } From 7c41949f40ce686c834b7a39c7b25fa8dc7c859a Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 19 Jul 2019 20:27:27 -0400 Subject: [PATCH 276/366] Update bukkit adapters for 1.14.4. --- .../src/main/resources/worldedit-adapters.jar | Bin 657067 -> 857125 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index b940ae841de83467e67a4c60e56ac37cce3aef6c..1dfbc9f9a8037215f08fa2a500dd5a9840d35e02 100644 GIT binary patch delta 155956 zcmZ6y1yCH{6D^!wSlr#+U4xV0?(PuWA-HaE2(F6;hu|6wze{}Y1%5>R;g=XE0h zI=~BPR4Imb{D@&|-};g3vB{}}3;*oqt}X-gUY~&QDj*2)pN%vQM*1}l^#ri|8h3IIpnuIlbORW8wTa}y90TE=Srh>U z*J%(mMkpBwSpYn74eH4p>pA9At-Lc{!P&$j$S z5%OgpB-2QS3;V35m$*td;IlYi5Rw=07U5r9`?%2*gze#fc@hnn(HlL2fr`-ooO(Ve zlah^}uI2zjTGQ8Tc&c7o_k376=djj1=XdJ_rayNZ!LpH|E&FTD{U#4+HC7 zQP)SpGEv)QvgCei}(dWV4%ESSsW^1pGEv)b4G-E z7V!(Z#({bk@e9iO4*M+P7v$dq`z+!Yq(lYvEaDf0PX~4U%8bYe_4gH-Ou;^@_Qgxj z4n_LPBF7Dt@rri&pq^#=;?)v@GJi$i-$Omi^u=~94)s4BAW1`2zuLabL&3i09a4e9 zfc+P@tPQ2g2v7ceqnA(H<9Z+y%m8UH7Zp2;shx?7OQAxI4NwFtv$%g+u5*7{Tf3D= zKUV?nD*zFG2bO4mNo-utW9+E($zlz5GhbBG?$Ea#}5|~6_)#FTuODmX~-UDRPgO-EJ@DE%S`i*3i#wSzBm@F`a%T8PvLbn zrJJ>9AN9_s&10$#2%1g3rC0m7yWlm>7?L|6f|U?3k|AS|V5 zE}hk>)jW-GyGp;krd1@@rG5axTmE#)+qwc zSrJ9zx~ZM6pb~>^IpzI-ZiFNiY{=q?g|1c4Z6(L?eK&BVb9-v~n+=E!F!>}5BX(_% z1PE(Axkb6JY749BdGl}tcelKQ`QKZCp!{CR6$t7633~oyL8{mQ z!}>U|j2bITJIntd^IJ_z^UywMm)kr;v?vy)IJjZXY>*`Rttjz)wA(V#D3?lty?G?8 zqSffV7s@Z@dHrc=J=P|t8#3=!`gS$-*t1xHv>ll4!P*6P1k>zfc1fuv&(GtXR zNLx>Jn4zcDvfz;||0QqjC5*SsYuQKH79O33yu%0h>#mlv0Uz)A#W*zXH5^uCv{rfM zIx5|pRce;DS(c86+C^@KSc|hKV(2DIlPXsq0TT{1K#AlNGbtiqj-$)gacG!M@H^OB zx?Lr9aa04++J5OeX^w=R^W)Ct1dJ};_WWG6yI}aKXt3}b8X6f6c@yvVKTrmLLmPGo zcRsX*l|5{J=`8`w<%?2Ksaa5&qPXR{v9|@KMd2Tct^}m9n-;W*w*85)T)vP+-G~ik zwlZQX^OI1$n;qetiRB)|v?*p6OZ#!5%_K8m=>z)G1D`-+4L`cU+m4*@%jzEX|EUu0 zWrWr}jPXG#=Rh*gq6{d5Cx9Fq0ugB!NA)-xiIbf1%k5;QXXUhvZ5vRg+~b(-bK%XA zw0+i_N^l2$*fm1PjexvhW26!1#h|Dt6@1zas&_a88=j*5^yHa115HuoQJfq<5UfRs z{+J2UZ_sybuc!7VMOllCBaTh4d(wm=vg=3Xl97A&*DHWUMS0V7<2q@wK9lFR8vpJ; zuxYnzqBd-h&c`9j(nDP24q4RX0QX%`UC29UEAd~Yuib`bY&6(|n=q2vauRW_1%skw zK}#jJhKE0QZGX3H=wj!8xYhOgrb*e&*d|h$uH&fvn|ZRWZ}fwOowL7Pj#xr@FqB3Q zt`g4RPuGK-*tX!*<=P}CYMp9iqcSzImJx{G7^l8>Ud6X{i~3*sCB0>ditTIVzmx53 z9Jevn-G5zs&2R_}gWq~eErV*Q$B$Bqmt)*iy9W&uj}h3tGibyxC-;%z?;?fgY&qM| zjd6RJGz?ue4VHKv5tvXtNbUwTI{L9MHiY3Lvby_6?Bm2NLPY6Pd+OK)i;YPnWTkJg zlTO+KL2d8xwwR=<6c##m9hGnDdH9Z0hIg>4&P#JwF$~q6!1%1_4%pMS+P*<{2r+W8 zhW(7}`YP4o`I~X_)6l9EO9{Z3S|G9do4)k#cMB58k=xvn3mW#7zB3c>tF0}4!NV+G zR;+*JcJdBcZ!4{*m1C(9d4}!jt^0)?vGRY&+ z-F^`OKb_6;RwgWBI$TzqGKf^{HZB$IsF;%>>A*$sJ-BU(qcg}e^=q({Q~jafl)D9N z4;1Oa*~2=GQNxD7Cn>!S)#Q4WDZhfyDVrwvS#dMO!s-o6M*Yzfx^6p#Oc;qoo5TklFNA!9YyqoG3 zxkB+)|0euS^u{OfKK{ZTt;(Y*qJ!BLgzpokE2^yQ=q-Skw{rnhw>gr#sH<`c_KW7a zgULV8%QRmx3H6JWJAh@Xfy93Rk{d!Rm}PbHg>G;iQ)j-%piiHst2B*kVgocsa5CcK4X_<=^>Qf!!2n+YOP>1C`Y9{vBs4bPLB*r;iNLPYMnaEMoA_g5K@wtA(yUZ zVevhA6xW4sVTk^>P`tdeS#uev+tzO2Y8D=P0TKlt4D(q>E{ED&VD`k7+`c*Af`2^C zsx+1T+_cEH%-Nn}^RQ742(F1PvP8kk!XLS0YFrt<`V*NZ12CO%X7V6&Op(Ru>sL+t zK(3SS>pK&$*_D?uuB)>kS5!<(D>GWoC$UvvkUC8JWKmV$=;CO3y?nS7x!dQ5;!$RvWC_k!ILVSJjzV+*u_}~ zd(@4zENImNX&-Nq5?Zs(+=q* zLFwIet7V|duoop$H5gi;wlLjg?u*Z3GPP>Ulku5iuq>w^SNh1rZSo^^s7*%M{?;~~ zpiAE5^90^_1|L6I5}ae*%gLE2ww)A9K$?$_Y>sRjVG8h5pfTz(HY?ygv?w2I0M6at z(rM?m5qP4ZvP03^_74;C2J3h;IWngpwSB@J8c(2oBV}!!xbf?Yz4It#tDR~0zI<}Hxh zLK;EaGeemH6531?jXf$lvYvh7DR-oeBk&YL@mHq0Uk1yNY5OA`x-Kw4=gJiJ)Cle+ zy@^@IX|jx5L_8-b%h=l2$BG%D*GO%#sL+y6v8Id@-qi4VQ= z!9rC@j2efI-@yp`lwU^dRvwAbi-ttP8cZ+COYS}cHIDt zOAWA#5%O2QYwy7fxAuRPv2!v=tnR4$lG>7JHgr~M8W6S*H>0wFiN!K=rapd@lK_|g z>wtSw1HIlGzAEF+@oa~k4_0BWx$DZxfASqZ9tZI>4+U7`n+;5BRm0|YkKlo^Wkcar z_(ujf!A|#B{)c-oT+OM?#%RxGLP21?$*xW~>k#zB58-kebKI0To>HLpXB1Uoj*bLX zLlrfYZz1L5m6M0fvOKOj9@PA0EdfeaHPJ5LLuOebVHn_0JjBJYxh{hF^GqZN`SWyb z3xMrBi|F8F4MoJO9d@Bg4K%(Gr43#As+=0Fe)FGSb4qAMi<$#dmivuk(K*+naTRkH zX%zbjO(nGmw^3}j64^{8ZAaF=&|vs!I*+l7ou{QZPPW`J{r1+|sF<{JH3WIYMf9bA zAg^ev3KZaLVVot3)F)XYwvFKaDY@op3p&jjKyn6qA6=UA-x(B73f^OHOC1Zv-T}3* zK#e4wtWATu&=2Z-spIOG6l8Ov!){iIe&HjR+EhF_VkkLU4!xfigOe7ch|gpW5`%cj zvPE@-qw_gJHa^19ZsPbdHLgc3hMs>E=zviEjjw&D_JrF^h`XhzpU`?zwzvT)2&5aH zkB|aSgwPQ6p*_*HPDE|Yhf588TZPulhmAdrb;2dBAKN^EpRU;Df%Za$WpMrR(`6R))wLZ;FitQW7PHsH@+MGL6LeH6dXmhop&L3v(^?|53SLy5PI_2gm9Tbj4giA9Bzx)fDH);SV71s zq#?ogXPdc0n}WR$XT<9yTWi%HG0)|MMl$GT1~tYfJ4tmJEau;VmsWAA;6Rbu3DxCf zVc4K+_FQ9ZTMQDmq{p6iHl!O_jl>1)OPQPZR<7tzu5Z3Rsh!^I{Kyt5YNq$9G||Gd z!05~VxFACiWTZ;lavOjg*#pC4-6<98ICaDa@$E-DjkqEPV@dg(CgE9tS^cIRw7mvg zzYeWlZNv0rOV%TTPX?lP^!&SK`xq0{j)(F0$%{ANL6w0$)KVqi2}$)TII6`7r)zx< z9aJ0QsP%Kn?i7y0>|}fB@mJjrkFTmnbRsb|!|!LG1QZLbPB=-o353kVnur-3P_ejH zYhYlI31A`?eCVPPRk&#HGGoAT5cQ5E|0ql`6@1?kVYTNcCHL1!j-Q+C*i`>58e|M- zMBAqrCGuEdjp9__CRaN%g|%_hpo{Jop4WqRCtRK@1>#`v*71LZmOxgK2AM#EeVJT* zw*zv(AQ?SN`v9M*0_yK@r(UBCH&EW`StF&0+$5k87AA>n${Dxxc|nw2mV zSJ`D2KBCo~t6V%GFHZn0AIi-Mh2hz{c}$P+#X2^h6_Etm#X7Ukzj_G18+1>W2Yt`>~}1ivXX%V&BKXj%_GzW!I`E zKuDLvKs5${5@gDT9NV*LQp}z7IYQGQrIo_Rp1>>^0ml>`EcPoHN?|~?Wdp8`C%s=R zhJfx1ipyQ3=Cw97*~+8 z4ngK}N3Iysx%B>bk_NLGff0B0TW+65-kQd$eencua0OH3kGIz8iMuscJeKBZV|u;j z`?MiZwam5zDerV<08%{NDJCj1I$V@mv9<3}d_Fwr+A!YiQ*fI6ChV5yeTYTR5%_A$ zvNl&jEC1`-?1g%eEZEQAlu87@RFOmwsyrYYo1@DEXbOwm(iBU<-W|Y3EEY-_rE_--~P2bLe~+p9t5~X{+l5!*FZKHy?M@nYc($IZc|Yk46HZ^$`kg|Q7oHo!DhefEa20>0EoXE46wT5BXmL3h5yBq!hg z#`A2@b^yMgG5<{r(?MsoG;d4RI5pTMIEEgOynnB(E5p4cy3D=KCn`eh-^FlC>P#NI zQVnA}w4$04_NOK$PBfWRDn!46mOxC6AT9(|Wngl&Cg35Yq9DUmO~T(Calm3$m>u%| zBarLg9?P2UXM}$z0?%(ra$Hz$@UFUXct1YIIy96EI)=fr8*6^Kt<-|aU;2C4ci}XY zlf9&?sAu`7t{I;HJWhWUw#1O~nPE2*hSlqtm8pG;7ksF^(YeldnaUd=wgB9usPOUsYH53n?hJ zxo5gaL@=g$sz?W?PhxEOLmUJt2rX-&fvg7?f2N$y-OIvV%FABYTLp_-ivH)YIY!%H z*=D6xa%tr~+T;(OM5UO=z;N*14h#H%Uk0Vi7#G1M6T7s{bo!dcCQr1Ef6~~Q>hE&( zv2+!AiE#_XV4K2Ww0C8CR%2^6H}q8v-h0_vm$TA=wiaWmeR^v;xn22N?GQi^;>$2MJSba7T2X*B>~dgyc^sDQ&Flm z^etUzImGr~@cS3=B*39oNQX$fa+eWV1apUKFk>)<1a?>K3*s4MhdnI!2A1sdPi1I3 zJ_UCPt-%*c=Ti!ZvV&m0DXfGjvp<{U^8k91%;Ms4P@%>}A`1^P+owpXrT1dYe>_Ki zEev$D@onAR2UlGWUUO8|`<7u%igDl|`glLMxgMBq61R~~HY-XKcZf;5{k@))7;wso zF+N~U^WdUukrCA$2(J(LdQmIFJ%Kcr_widGAm99DW#NX3Ip(wMI9@z&xgM+1ssa?mp-_YyzEcD_6IhlP zvWC~~G^POLqHoZzO$Nh)QG1B~GS)I=U=l5YYyMKeDoHZR68(0mWf+@D3M}}elPj8H zrHH9x9=}^#C?FZzOhHK0Qj|Kxk**7IRhueytw`4~DW#jNa?;eG7E&__H7RLy$t!}B z^s@6+Xe!=K&QniP$W>;9Ser^{Qg@Is&U~)!DXdA-mn}+hD7t-gRZZ^+NHEj=jtkEU zwk^$4NeNO~40dTE94Selr%OuzT4%1tMwRslcd774#^lIbcw81=p~Qy!TWU-r%pWv$ z#G)Zt>|Z(4FxP!Q&{I+!R7yVLSzmTGfD$9NbTr*=(e)>6TIdu;Ql{EH;H5NmvO>@$ z3BP%Tmh{bh;3* zi&BDbx=X244W4$PRp32#BQ$m2pSO2M5l-FSfAnvc)X>#loRY#2e`^-tE{=$eS5*_l)H&$2DF*-itJZ-T|$nf%ENy)b!H zph2x9Z_GTuVAOk<|IT=)_3dNBo~v9;aNoSqe)HyysiQrF%nQi>ywFmjAZVN*hV=o0 zZ#b`N!Y{tlSKtzl@Y8dbXST*_$j28HoBbB7<1EI_*J;izsJO(=2Q8(f?0n)mZre#u zSvF)|vN1o`q=)Eo?B@?{1rFJLu|AR_?g!C+rTh_G!mjx<;o%HviEN}hg}au^IwiJ* z#UlBjVA+B9G`sCsdCbkiK1XS)m|%wm+>$|WRzQ(yW1MwIk?F9CL?}PjGv}~cu}ErC z7f{Cp#b?u8VQcT_=UqE*qg$Ay?_lK<$!#6EU&;Q(wH(>521#t`qk!$NkFb0tr2BJn z{Dvog_qH1Bk%zJG-68OeR%e3**x61_ZjmL2KcQ}e2h_i5$K(uIIz_Z-+P{z80!Jq~ zz%EM5@*C2f$InK^AIxoOO5I^$vn=lMZn{wKu1c3x?0Z?(gXKfYbWFBx-O}#HhEo~T z6d3K8?YDj->nT|k4RK8tJ1d-akn5Rdl%uxh7yP0ZOZ*|Pth-dxJ1tfe+K@@5dq~XD z^l{TOdy2g`5nHaE@uJO`fJYy~047`=uKn@zLux;@tx&5<(i$nJ{%Y-*y}-pczsga2 z<&TH-!fPl(4wrrH5{TwLeyxiQ@?EJJq#Z&RUcQ1Rxr>P6Y(46S2Jj^fBkEKc#h)}8X@DHeJcn&Sr2XMj&rOOp#l z!DQx~EGpkhzgj}ItzmpaS#hw{;dB3^DIf@u-Ee8S9>&hzmlwSGh;Hbpm#cq1Xu$^O>j?W6W5c{P`KX}=*{Tbam&s}xy zu-<1pTjp*LsHNY&CokD!;A6avVco~LG$<79ZzwNcQ1k^Qeq$OZTj>9t)v`+zP-U+z z6D!(iF-Y~J5UO3f0=?8QqVC2->GOf?36TUd!d%wksTxK1t5dYOt=tgT zr7=bd_o?_VbzDw)uhUEX5c$rBz*xz0Bgh9v?V=F!+L{lnkp1BJJkMr_vJuesO8fv< ze{Jo}*B_hNy)}Pty{S^bbug{=<&-UYCgFBbTU&m%wiY*!7p&?Hy(75R z3R`EkSGIzs{0$Xm1%U#msWvwhIfrn%f<+Bl+k3{9%*66)HSMM+ah+B9D?5`U#4Xg?#@g~7xI-HmDLxw8C(NAR z-nCm=Mes1KbdIpkjHY^DB(@|mB}!hhOc{=seP^onw@|BWZA1^ZbF%Fvw(}6*i1VFt zOK9n3$}e0isvs7X_FSKeEVw3eC<{Jyg~Fd1VUQO6nY!e2pT%%Pu^PGeN zVX|GFI{OS$iX%Jad*0d5nU3H5MlWh>!rkT*H%f%Y1^!KI7v{vnMUF3rkT@y?cAOct zl7RTP&r@|xR!5D7m?>$l)QBl8J<}7qf={q$oy1@EQtyOPv3iJ2%eJ7BTSEFdo`l6a zDryrC-8Ih`2QbD?u50nc@3u`}T$xfxGFGnmOB_@9N-;gUx9X#J zY3i!c*#HZ6T>yDMU3E5IStl>MVF3Jx zJYZt48R!aE4J(zQh@Q=WD5o=EoeX3V9)!&+PE^_{4`!DO=;^fsZHM<@r!wXt5Rq@w zI~DNC2HboI07^xgVrkRi&{u0SsTh~=Y6h6E^MYb=EiCQ9zoXH4rk% zG#Mx8Td=e#XBj4#71eX3da-t}Y3ZvK%e9Pycy$7z*ReovBh;|xnbr~P(9?nN@#yU8`eC-EjF8kW1Q2DY;2Ez_#}rfl^Wj}7?wAvHqOb~U! z6W`7-8tC{w-Ysdq|4nv;NC(owjm5#LPfa3epLH8<@%adEkkJ6`U*^oAw{3`-`nLjX-LY^zYaEYY9aU~-JDF1!~0%DB}*d>4(%shIIL_u!-_;--f z;OG6@(8L`qrZpO|lXQnY2i71~f((n3;)=ZfiKH0?d)K8wTX)4V2wa3& zMWAlFroF*mk{u5%*RWjk_ii)w<_=a3Wxs;Jw)@_{CgdR^BySbQ6d~#ZlXMO=deumM zI_*<+MT?CGsw#|ol?g^h28A-rrREFys{j z=cjoXxHT6DIM9mu7+f%cNDJImwm|u#6VCb%Cx#fIn2D9T+Qcd&Gd_7KxtB7wODtCS z28((NlYbVRm6nvv>({VDLzgy^ySrqZtHUmGHlYoeNwJ5Pz@T2RbMScxbza~F5h63NxfC8RcE+j z+3pn?<>b8Vk>e$SS z!H(_q>#(oQe(EbMm&|Pj`DY7BZ0{$u1-mnPu>VS8VE-k}6Ci9!K*Zc#g6Z z?g7>I{;9K=+iqtCgB@^a)vRtb40`1`O@Ky^P5K@=cv;h*(P-XVKXsR|Xpl`E*WXE# z+O(&pM|T#Vs={{Ugv+2Iq)JykY5UBwV-Fsp_|tvP#c)ZxOx?46Q(K|fe7|q>bd)~F zf*b$iKuFg7Mf0rZU`D%t(c7$)vWPoLGWn}xQHPAi<|uL`PAc$~4>7wdychnQlYyv6 zKk}kk_)CKlKG1g0b~%7J!DE zxS`+=IJ|^<{)`UWdAHDJSFd+Vl?iXxcxG}-ud1DErq?Z;a8dYoXZ1$~b0<}ExChuJ zCQ>H-;|J+>4=ur*D+5KSpO5Sou~VjTz)o^7W#GAw@}_ZLaQ3*{IiW5lkK$buc$4WU z3H1IVT}7nAN$!xMCQZrF^^O=oWp?AKggR&L2Dk`0xl)~7_Mjh>LCx>59_YwlR5Qy` ziMkp_m?a0G-5fep3(kSYk6sZPw60& zkuPU}jcdk$cK`rXBl!maGSt64Nw%okwtv;b&r(ERh9-bK*AHVL;MNp|h|rLCvMtj*Ea2>;AJnGF6{AuJ6wKa&KoK$*)kFDD z0Y;@SOs&@V@)7l7oW7&uaF)8zvaz;_$R>u#NcBXRxze}GnMk7eQPOL{U@xc$mGMN8 zDfGews{E3gsAJv2?%ZX>*)~#MoivTyWENZmDsfG$p&3<&$(ocy&Gg+byGLnh2fx}y z(bm5+(2BKlC=?A}Gk8T2gj%~#8FH46R{%e9^=#yr7^Ipf&>`+$;eZ1VQ z!z8QEuZ|cg&SJ&UDIW0v&gaEY=cAOHW35;`eN^O!ilXv&8$We18XrE!#f!;~I~q1K z-MMLD@`j7S3r3SbxiJv-T|zJS3#cqguNt&jlI87lCv_^cWp~0hC3lAX4No^>HU*My zU_y!hqKL>Uy*B<;H{!%lmcH$41lIBT>_UIe^%M*H9;gi^q? zm)yTWqC3ONfnZcPr~?v>d6Yi0nJML)$`!(UNgkMSyLVPZ3U6k=7sun0{?-)6m{Y>!{|h) zbAlH>(k(Ur6LPU%nBr$0bL_ric;C?R{J-6un;YNpM_Tyeg;_b1o=n>VlCGdODy8^t zep0kF%l)xay6dS@8|YEPa`}}ZX^`VXg0Q6$pm)5IpZ?Kk0N)!Nw!@Vbhlp9HhA3gP z+k!0`Z6hG*8%ku9eL9=GGl9(mwR`Jw_6}+1#;nlCryR>tdckhmVDQHOM?6kR<#D_d zQC^u^p7{EgOj7hhU+S)_t2)L4x0Pwbx`N+G_usERz&>2Jn5@#@zTF)N-sHS6D(|VY zB9n1M8oNlai06_9OJ4b-ZaDO9@`K z^tCGA@4-jB7|aLC@L4VjP0EUI`0?O25v-qdtMQ2`}eKrk4DUf6XIao8^vzTjz}kBM@s#14@`$uB{YXkA2^;< zT6msw_ipC4AScEZxu$3j42M4k!2*AUyR&@1KR}fqD|<9fHG>5RmAwqVy52#^a5mHA`AT%XhQ|NphM*M8~%K|v;L0528ST`}D zw&wSzE(=;$o3MXR%VhwX-0Uo_LN;K|*(#PL6nvy+`?& zaZlPLMHc*Se_ouPO9Sk=}N=Q`5AFj(L~Q{e4)WpmuR{(zJfzV!4$Rd_O%Zn`!ysRBi_y+t^_Vsu9WcP z)r@ek@W7`)c2akS`PH7cAUD#tbo0^^jU>n5tzwZI{!reVTYTq3MBQ&y7kmCa^;g97 zD2tm&a)MFVhOs`GVkdNG`eA(;t7pNaMq!SB0E(ChC02pb*n3pj_&+dWf<|d{qJ-@u zIq*dx*%dCl+qjhCTg`#_;VJ=@#!MIw@XB&%|Myp#F9$mQZUq&PC85^?9R~m_*hT}b zCxn|Onvr|LX)R>a)#p>;!ct3X$O&CX5bmCYLfZ+zmu@4oVbI7ioa*q$c$%Zdk4DbB zyYX?OH)o#lpJGaQk7(GU@h_W-H-t&3*doJ*GpFNb<0h*+(R{31-J5=($yhev=Ygsi z@Iw_Ak_pGWC2q}CoCg!RgyeV^z}=0>OKy@qegejLe$1jOCyQdcVN*OItpmnb23ofu zDd>QLIECr6J;ARP<^JnZUyjwyXHdKfb;{z=G$zT&8uyXIvPZBFHr+qoWR2Y)6k^yS ziTQA-KR)lP2sQeJQ3P4It>Xz7DQJbZDMD&|YY5NY-@10A3h21_ZfG6TdGKnrLXaIox=Y(Jqgi4jn5%a6&Y~-#hL(}cPmcbhVTH*8AaU8OZ{zcpQF=&QFix zq8LDB8^@)X5Px9w7jPAwB#bo4S(JIp7AnKT55Vg}PC(*ep9NXAu7Y>0%x*?Nc4tU$ zZ&5S4J#qD@9Z83F`^;9P+d>8{qvB=1`!f5O_SZF-71UOa$-$ov#pAi z+*Dns84qzB)B+;jepZ+~HEXRBkWP?Kz!?yfj0lGw>PvmZ{qHoDp{ZWw@%b#}7x$Yt z`fuJq1e^iF&u?oq5m=r^BpjGAC_qmm*bP9A_3u|x#r9|@zaYXourI$SQec6h5)ADe zrIII)YB#3GVPu9^4yBu)?X`lZu*w-0=c>R#O*G|agSc7%%N{X}d{2JC>dlERd~>}y zcy}fOxr0=&z~F;VuvknC`!X0D3Y`c&R3}bSKDT`iod2HHD}i-)`dnIC)rx=<+(Km- z$*`l5bX))NI>DEku$9go;xDJ20PA@43G>Nr$|?pY1C^YN|NbvVuGZXlZ4F<<%c z0|wEq#*xt{U&@_st(ziJd+6HT3+>c6IR^)k0{-{sKc_jH)ohz)4Jr-3b8sFGD_(X7 zHvwuJ+yWd8=>h^&+R@x_cJmHB>@hcpJT4i{&109%ram#2KGjGSY z{7(rBfrU9Vxo6orerMIKT%m_GfgKSQjy5rvG|R0&&Y-d)t|Bwv!(mF~3YXk0=@ZFFbHGu~}<$4U!F z?>lQ(p|77x>i6(PCH}N_Lof40reAOT9E-iRx$@svLYw}$EhN_9<(t%)%>ly?08BK3 zV*zhp7p}J3{@0N91i*_|qytz304iM;wDta3G1pcjPoHVZ}vX{VW0OEpOXYzV3b+-`KMfotl?#BL8bS&z(A=*if4T<=o_YgI4K%X}OJb?pkaRep z%$MuP6g{4x=tu}jhF+yn+2Cj5^sWAW7T4^Qdyc~A(CvfszWK*)njk8bvenB zS3NnGqblxQi5~G7hn42$j}znioxzE6HQN+cl28jWzuMFcm9tE~cXe${rJ%;6X5`|8 z@q_WKqV1#}W%Y^%ngO=v6)g6$Blha|$oKK{SQZMr8ZPt~_QkT>L2|j(Z?}WzbU%gK z5>#?hK^8+Dhx8hL4-FlG6EoC*xf1oGhmy34I`dm78%rOm^BjKLmeFxr>{JNNCstdX zM3|F{hwX`oDU?i>(O8ag{%VS3Kc1MJaN_3?nV!G4(-cA);XZlfdJp|u1x))v&R%W6 zesNNzH#5{LbY@(fz@~$9Bjk+I8eLA9Ud-Cm=SNAqo;ltMsuZ3#IO5M!NRiajc!E67 zI@RVz=vVX#7!N6Np+B6qNPbD*&STOly{?DM{S2TzHWNd_MwA38wv{27b$c`IBE`A! zEQ$uQxfu+SDo9%nkH-}*lF(;jx7Ii8`VYLatBeIZl|@SFEJt_`JCp^}WaNodlwQUM z`15ZANS;5ixk>l9U?S>rDHPt&L@NA_PRQZvkh_yFS<0iE(t%^^hYf+6Vy713y99)Y zMEwy0A%))UsK1_=uwT}b;=?<0awXpLGy&gj=+ExhQ}DerxhV9+yj8nE=R$ew9L`ko ze8SH=DgI=0b*))fnrGrvYDGx!1f}yx`yj;a9P+M5;gKlvUI%n^`dx1(Mn&RJe37%? z62Y`?t3ybrjFbmo$_erhg(l?Ea(FxXfl+J1Y?`>L)G4nkIsGL$Y_ zsHwE~*gp!K#67|H1v<7(WTacIL;a;NO!drF*$8=O*IiQ0 zh9V1-WABZR`oI;6HO1~qNeN-c-e9Mb9+vn&TzzA3WNXy!B$?Q@J+U>J*v`bZZTCbS z8y(wDCbl!NZQGjo=A3(P)%Tt1fBRS0uJykAS?j@y*{Q)W-**yalu#x3>8LXR3$-5! zuuR>c5aH%&?M4}1HSL-D$;`mgroseU{6~hPRSLrc7S#0M1C48%iK@bn-C8P2uN$(A7UBL!DFE4J2&Y;%hD_Ug%GlN?V`?2 zF%8mo`~7^TQu~L_vu&dWRB_X9VeT-Jqra)%r*bKzy%P z9{x?5y#7v z#w$u2^Udlwi! z;AT@AX!yK2DAWb^OlqG8`W()pxy)Fa-*Dceok0=`FA0~EF(o}NNt;(fc5~VkXBtAg zL5=MCI~5?uWLHkVU4_^cRPu%93O=It-hFAC4O6tQ2)jbJkt<9O9V?gtq*8I3!YKec zWdx{2mzr7=&V-*r8TZkj6DM&LI}Ji^FhxeVvMo~_d_#?}-4cjRxV93D`R`bTB^8AC zL_{a-wX)L5iX}fztnnOfI9Fd*=)d0{Zhjf8B^W}D#F50297G*Ti{H&7f7NM=I>_)>Sq+tX7NL9VeeH0>V`mWJFL3ZrYcEDFHGC3L1@+zk(3w9!(7o9t&wDJJgPXNen71@7so zu-$d}%Zr^eFUA@l4NtYO*Z%r$nzBn&JvB{MmHrn~h6;}6q`9Z&?&;89wA61&^+Nq@ zV5Zf<;>(ZIwdv}5>rEL5jo92%bsTx*{fz^A9?PuvT`z?L>nf^?1RV10NB zQK#IaWt7BX|H6)yW4U+|lFOeY)n;y3X=ou;2Y`CbVmQnkeuwIt2(&CTRtKSrQDM^_ zbX_rKzoP#lxa%#iAsie!If6*(&y|>HgEWbqpBEPB61s@N*f!zF>;d&-uU*I8QUpcr zY?v}kCpf;xR5KTJTFWN5%UOUp!kWYSqu#~4xx}AsG5PhJ+FuCzVCy0Sd{?QmEfb92 z-ig~vkT-G%Hx!|-b<>{%+NFnG%Ri$V@Q&?f?E2o}ueJG> znqupXl9vVbXI2!BAf(E(J)pzlY`R;QgNUWSTOa)7g))qdwneZ)X35j$?@f8YNmxN2 zv+6R`dm;2ZxBR&))f=;g;oDgZC#j@esg+4Z9HsZ$=K;97amYIBJ@9pO{f@*6;Q6KgaB_P8;Xght=SyACeL&}bu62j zYV?=(8DHn9h>CG76(>Ke>yO7pJsAmOXlsf$(WB2H|KsiBBk>oEni8QtF-(w(tYyle zDI!~ns-qa3^G$OZNxp%eP%^3Crc;GMDrwq;4Re3Eog8yyBE3X~tCs4vs>eK)T;1NM zJ9c9$i*mn{6^ord+wc_(*<;$(Ef^c7dhKXQZky$(Jes^cZ`@Zuc78VgxDlbN#lwBb zW82G3Zmy!c#4SyZtbK4bh@(Pnl@qDumg_eCsrMkE_smf#83%Yu7OReLV%;LIG5jsi z=s^}Yt5_x)CK4;j#LI_{*=Kt?s&>^m1HiSQ_6<{yskO3k)zL~OH6it<;O}{}KbaVu zDoD-CK4YtIc2=fMyQw?5l)=Nh>9MPy66}y@Qef?y#^Y-?e~bnP=R zgxI1RKOvXWlp}l-=9(eRM~EeJgZc(l+SVe>cV z`G>hXR&V8}MEv-Nx$`sHH7f42)jFMp&b+hI8~L7pZtw6Bx1_yUcGh5-RcZ{X^?=3z z1b^j+MF_n6A$pvDPHLIL9Y{mY%lv_K#=wFaIfV<7z9$zK*`4}gj6*GbPc{#I_`J2G z!T$CP^Dql$V?*o>W&W}RMTthrn-FP|FwJPBi_k9mEj=?2yHeCj+@SFH>;J@} z@UeA(gSJcm#ZS4{us8|7{P00~WnfUqR>Ud@$a5*NDzfz3LU|?$HGVjNCXx~s(v!Xm z_lf1(%+-u#`w;z3@RHo*z%V*Zo$(zlq(w*ako4xH0iS|3PKP1EX~8hk+okJFha^%> zdRvx)lQIU}LHuYYu4g@&6S--pVPy*%?PhIZzPKN(MZLPz1}WZT!bq1 z(j7$`l`SI|tQx1COs?wyOd*ot7u7yBBIH(NqKn%m={DPCH{p#F_qMNj3|<(4e0r1n z#l28`^O;t*hhnzx3d?FZH-xz2jN1Kh%zA|@Xc z>XMtNhH<&+Qo8EmXFu;k7fyF+3vYhlh^D3SxZ={fc^+4qT~#UIc_mpPQ!@4KjrrTB zW{^H3aDdq}<5USnA((W#9x;)D-f&rP0DMRn=%U*qtzEK{<^O`P`f)9YLzRctLidUU z*jP#6%$A`gqtOI zG8L7VqXG$J9HgCn<#HX%>t4f>fvSC=VOXgg+l}25xY3m*XOh1#$fZR{!E_YXQ(D4PRl&RBIoO+Z zWUb&=yJxPuD*u!QNW6;>CuI2JiCX20|JvhsK3MzwdHnb|O_=;Lwj+-NeFZo4eMlI` z+<`OFFJsqZezW}`5NGI=AmRre^6q!EA8!7;hydSN=rELrT~Ko+7&A#1n*Q`ceMzZi zi^YsH0v*>7%6CHzpnH6-vx`kCX^jC0rV5M%!0aP_TMxOal@LvxY0_zfRlsJy8R=Q~ zCufjeh8Mo*pfx_IdeF5E#}!^8rc!*-c4%y*Vq1)DU)Udup*-o2=p0S**b!E_ofj`Z ze|jf(+XpdHzK567%q?ZI)Id$8mJSP)ShY2?4sn$BOavCK;QF+khmtyPe^}N0xq<{b z;8sRP%dUqp`K&G}6Mr?8dw*iYBP)3pKM@yLnwe$*tPS%~=v{Rxypp;HNO05@CDI<_?cyipP1nOfxWbWgufPj`Vpb~OiFE9-*J$s=?{ z+sJtb#mq7NzqN91MMfA<=mgjK6XdF1-J+At<>-(l(u7H&KG3$6DRQCY>0+)Y@N0?%X>dGUggqCTRi#fnqxeGjOBS&I495BRrE^r#;!D84_ppeww`mXrh;V!- zH2eF=Jr2l$UWk#r%02?r-m!H=`QJFVe$_wr%VzYRoO zpbx7EB2fI)HF9Ug#89C68Se2db;pP~HT>%UijWur`koPTPwbM63^V-$>KbJhRY^E% z!1@ku0RN6=K*vtYp2Sg`I^ECTk@~Tl#a4yukLFXX_N4;~ZXyVLwT>pC#AYUGo z4kB6qH(eyI2@LDs3`5XohT&Hllteiagr3lv9vsO4C=o$Ur~r$z%yS#6)J#n?FXwAz zVmDOmlS4$uvtyx{;L9R^!NL1YxQkE= z)4`8C?77=*wjVbf(3{M&qTz4qX(n;|@pyi(ZJEg6RC2F|uI!)c&l;TWE} zjk?X7s``;&eP(R>LhsXl=l4haS*BCpDOeTGcd}J>HkNLrH=%=^%_mx$@ljfhq)5k5 z#@eQq%&TdQU7JQ&sHb(pT!*()LYy-7SMV-10zqF3zA*t7WF)6O9P4-ObUdm z2}Ok!NX7&KcWgAD+gqHt!gb_5WMZ~(dkB)#gyIIf2hlZv;e)}0ytlxKkmDN9@sv-| zt?{*^Imi2^K_#CL0Y!C_oBH}ktddvKVjg0^s!E5|eyz&n4aA#rB|GYBnUCS&`?sdK zep)a60-^QvEZQjc68z~dPAyGQ+-Z+P)}@$wi|%rEYK&PJhtLHxxi7c`!Ou$Yq_itz z+(yiy&X<4D@GkN#A*0aiBN@owV=Z=m+=$leMDFh#FQMJ(0LU^uz6Ngpm?%+=-&QYh z(lXbQv6f+OORga=F5c}TPhD`nhF*$`F20voTK) zj?f-lq`}+F0hsti;O@53+^k~g3W)h4XjcGUmrm93HoxZ`T#GA12km+0QGPLBDIPEfEf0f$d zK?{!ypu+3m)`uWk48Yawt%sLg@AswfKdVL{3(qIg%bgBbah3=6dAEBNP!NfCW2#7aeYL%r`I}`wYj2P z$remtDV~8Y^thTCiH79Veg3^U-+6UvS>_!BO|6Q^Yl1{PaVL!!`kp0Dkzn@yIEu$1 zBvVkz5)ceDbeCzoEx2=5cx(?#3zA(+kSH_IZp?!g&HK+PBAWmX(ZXt#!_T+8u0e9P zH{7iSnZiCq_M;xqm(m_Fr0?7n%f17*sCf*nB~HT=kZX+FPHa9t%V^EfS9&G?n{LKjj|Ahgj?BCxSi~UXdQNt> z^T@YAa1Ov@mph;zDXO{E>d0L56(~G^`5Js>O7NJE%8#e#;R3X6cu;NILIAa3l$e~A zr6p;di|Xd2HIx-)AHG+mx~jI9XJr&NCNDUvG+xhY+IrVM;6jbu+nzTIIjRJS)=QhJ z%BdY+pqQrCbIj*jdy18`(hS?Y*&|9ZC8*xD=F-K!j{|lX3#k<#-j1uNGkXp=O!FDDSgom6_fofkstM4^n_WfQ z0$ekDp25FEvg?RxOPEjbA%=xkOM1lp4Ri53G=jxvFoAqU|N2*z{n}b%SYQCpkC5;c zXzi|v+6FLDALBG2*Sv5=)qu90Rj)XLYlDpW)u&^Q{lwD${Jn>oY;S@?CuU5r6Bt9j zx0N?IpG}UF8}*BNpV6K~XN~*iYOn?0B4c2OJkFB+!P8FojYx*9C&wI0=H>f%RyHb1 zTMxC&DxxnUV}cDsxds!Hc2lxQGP#QzhxY|3cOU>0l3ii?8fg~V9Zl{IwdGfYDAP7; z6$%6J0w?+BQRgoZ0Cu8Fn5`?Uxx$P#@;b)v&Zutg7FGhXAjb+ z+uSkiBWU!MsOqY%dE|1J?MI0AD>lYo`{qf2d*9|M*7BOq-@~hRd_NX%uymSdy|n?e zw0Yh@V=UiLWh7Cj6_O8sM6^ap569p&>FWJTo6Xmneq`dt@kKjg+A#f5daY>Ld=8w9 z0qL~ws@=1Y^`Mn@Fg%#BDyjliNkc@?YdaXhzr0u7DLEgAq~qU?5|tB@2-I-|jtMAp z`u$A|Jw71JmibzU)mB1d`)U|4i_xe;dJS#U07o$YY! zX=0y`?RNj=#rF&B+I>F0v0mg0s_;?-tN>Z47mMX73loO6-Zh!sXgL}hT9s7u#8#?0 z$GkKvx5&0Cl)5w%3~-~qEG)^2hZ+z`KbiCgP4?7NPir4&b;^)Gx}qotd>6C3POO>_ zGK3}ni9u<2j2GBmVA(5~)NBdoq%C)NUuT3>Y~Gky+^X~~G{B0s#i~{^0NW$DJ6x+O zF;Raf)%v=@!{}VdsNOh@2bkq*xa?iNSFsXS3ZjIf-MlmPAdt51RUVmB*#K-Q&<|ih zozpa!?KRic#g5SIR~Co;sN(%4Ff%oLIoITltb0ol9?i^TEMUhIStDPO^}sO! z=wdKpr~a9tV~3iHtZKa*YXrb;at!H_GrhLOg_o4lF!}Qy)EO-Gj=r(&Of* zvA+6ULLc6oqiAmgr3LF9WW!<7CwG@!a1*bnBb@2ky@HqtQcK@@Wk~>Q{6&~<&0@U+ zi6kJ#Hc@ZqYvq0sguKx&iayH>OMhdAn)1oo$2`QB1DJ(-bZ@LchBHRY9WowbSl$x{ zMrhq>-nB_)Tv)G@*!aFG!n-NGDeaI;9`L>kLYL*%>^q=>`krb&A>Sd6Phx_@jP}<8 zcbwQC29nRAj+V$umf0G5iwY@8Ke(*Ya@rwqdQgD)CSy%yzts;NvQF}gQ)t>G-*m{V zxiU6sP{dPSlPnwz>ZeakGstiYk|JsE`V`LOw}C^C|Cya+!AYfq9J>Fl^vhFl8mWVV zpZF*#MuF%?C};$|DO9p?u|WYr7#ESuID7N!Cw9~87qv|xC{nV##|7va!o0Nd%v7kb zoP&;iRAEv(0er^=3DL9N_6HOox*jmRPpl462i_@Ig`+*C9|>oJiKCcc3to-o5rx;O z#%~8p7JhDZ$9wP5;nhz1iwmw@YHJ+a9(9TIO3l9swq19N5d0Fu1JvCH=?2#>vDE>7 ziSE(W4gK{8%@wJ?E;upP5`#l|x5U>U->z8vW8lwF{|0qaL;j$=vh<&X@lo4y27r4* z{$RR-^k;(ek=o+)XM*<;Gsx~f2Y>nWSaFkFsrpyLBES(~{B7;#`ica*M(Y6THuP_U zjD}ewzmoI!hP*&;*53m2hlcQ=`4s}eJ*a3xiKYouI$h;V)gE&gaY5S-yh%j(fE z;cM(l$#u}W$D6Tr*~Jp^Oh4Bs2RI!QjYg#L)5ibdHHCZ z%f(jDZBxuvdL?sa+IHG{df-x>#b(-XO9QM6+AnvvmRxotB$S~OAxT~|1uSt_j@Q0A zqy>a~npG1|Xc2Y5ev-*m@YPnK;^U(E=@ZR7)Oz~9o+k+O<*e+&UZa^rn_TF%r1QMM zRFL%x8v5^2v*m)*r{5NRbrCG z;jVqN6*;8d-ObhT?8qT=$PFfFgY0VEfc5+J&*gl)SEtA{=0 z)!>gaEY!s9gl6X1T{Qfb(prjTZ7RiUP;y7arJIJoEhWGA8Ngek&s^z+N@9`E(@=J= zUFmt4w`1U$jaap6>Q=;*%v@8Fr=q1w<0!*}#7p2*om09Q=h2?e9hJK;OFXEXI2-H6rl7v_*Sy&yC< zWg)K!MD9KuOFQ=*-0p1hvP}MF>uqAZQr@nNwqTd4xEv$v<1fm-EVeay^;c&$@R%3P zQJ?N$K7BbYKR%!%EysSaz?r@<-Pjc7DPug7aU*P$0JwXEdifS|Oikkx{!!c>ip*Ik zYlk;u>i_QgwGg#pmaBug+%7sR?(V~u2GMNcSwVQg3&Z-sr-B?3Rq2BM{c;5+;TW`v zn3IiuC!pu6akQw9`Zf!Spg6U}pkgJ<_Cv7|K!kHZ=SQU6gRb!(%xwqf?4?k4L&4Yj zZfxOb2nhCFrIdkY($ezqvm{XSqlJ&1Bhjp;FNq5dq`~{T8HI0Mz#@rlREZI!%E8JV zy3-=YW?~2lD{UusP6(rlsk*bq@EiNa@l{AR$9>nLNm+~47{yfABv-Ar%z`U?_{%b5 zb&IZdZhLx!^34Ux$luJ89d|=Afk@g{nBG^SIl!%VZQ^DK=BuB}4RlSiKqTTT&dw_; z;keOFGm&~8HmtM+CU0zzoRUI6oK2n*X^{c#bLGXN{Z`g1rQKIe%ip6IpLVJjnY}t;(Q+cmnd5NSGwpWYXB^VW{{SG|qWD{H!J08Xg1s8FXw8@$!2$Y1nI^NZ zJZ|cgY8GfSWs?|{HoEULPPJUnBF|}E1!73!8pce+Hz_|5f07=zYf-*6TQ0I3aT_OU zk!GXfW8ba&IU8R+v-VA$PHl%2H|%V&IP5t!N(lY_*6-_6e#ushAw7T~;V*j1hyp-S zK_JZYm6m>6AwO6k5b2%1^{?~M!6bQ)LhrtSpuh)d<1Miv^aqREO|}8{2kpaEwjq;1 zunanU>NW zED`A477DfL_zv6?48p{G7Q{RXhD%S>;G!^o)x$0!?_E~TN3V1k-pMz&3z3k(%3)z% z=Qbhz(72YuYhPko2YwEkvWKDtdu+-c1&ah@wdG<>;|~0;9Dy!mpnZE!US>L6s``Mp zQ~F09D-~No+l)xDy%_(Z#W#!}6dJIpmHrCS9S0-A(U#Ur20KT-vWXTs*CLw(;P`xW z(GlZ4fi4`Oh{1M2NKR1r0Dk5wEmg<+Td_t&%0|^i8~eU$%JhO^(3DH!mwn)iSP=&IlL;2shSuC1*%+nHB#QKgJG2>~un&1!iaFz|x9w&k! zSR|_q&49mzh^T8l3e?#0Oh4$BgwNiw?l``2V-%`|>Gjk}XWR(M0yK#N(i1UBHA*Ys z{PQZ1dhkqbVHRjzNj0i%V1zpASiW-6A(Ac?*dPhz*HM0LqR|$aDpEEhf5WNST?_JJzGz-2s#69f7pY%S?MP-*jcPTRY75;b?hrWWo zkDwvMaCMPnpEjHpg3uWX6ONEGDwsmVT-!ZliKKCV@@!Z7`SKs7awW~d2FT#~-?AW; zgv13@s*K8`E8)D$Yx8EZV&Ficw&#%4V|Z7%<%30LRLNLcjSrOYZLpN zDAs<~l;xD<^vC*|wWu`@$1*0n;j+3;CL#b55J!_%eTy012&WsR^0~f?EVcDEk?|;* z^~R_Pnlp*goMd^^yv2UeqalQ{9d#|#ZxTb1th3}qnA{e6yiS04AHKEynWpyVlg$N% zGKjo>Xf>I;c|Zs-6$Ih!%qSBt^=G_FMhzY%@& z=)XFcq3&bG+#j*scKdt!(8+Fr0Rpssnd@=Bd8R=(P_%ST%T8@p^_yC6Dy&;lB2IfRTP$C7J)DPb#gcD<;HXq{e{!Ix)D^Z{I(@&Fh&( zoTK5=&MbKZ<&wwi$WvjE#v4oBnymU?Z9?Ko;nYvivd?FrX5VhoO0tOxkIEGdfGL4}kn0eYL&Vkh9=FXxZv(HNNYKWltKSL@y>AOu zX|p=RklK4oA@o4kYV25jyLYVpKH)fCWP|s^{*IRrE|0cVbPqVs@uaV%$FDz$eex2V z@+A zRL%ZQ9~d)nNK%sxat7(sQGFK*Ear$H>6A*!gSvd&tiTOB^6mH;!e>{ z=vlW|mgzD)Y|?t;J)pV?;5c)u&F~y&7J)WbVXM&nGLm6GZHfQj)oFMWM>w5)s?lYl z_RioeO^Ql|qsH_rOAKmrXW_#$!nEWLIcI$anN*aEkg$w>gj-D9(d&(EiCVgdSt1{e z9n&9Ye+A~3Cj||wPR~4xr?V{5z&Nsb$+$pC?#~kriXjz$=57B%EgPe6M7Sh(M6lAw zcqFfovk)}PF(P(3xbSL~1cquXvC3n)ZchEg*3iqYYb5vSB3LrhyK@do5gIuuIkE$A zJM~Yv;g+Tc|FH`Xj>{Z?P(A-4lauGc$N_8W9zThKvC@)%kO5^84Id9@E zc4Pzb1$vi|1pNEKe*{9>2paW3UrE@YEIO)?)Px=NcDhewIA5-Ln|Hqby}=ZOScM92 z*6M9QTR_wqLL_W*u{mlUSM)i9vTGlTt-e@7(BdPI1Y(XN?g{NY7M_H6N=OdC5dyZC zge~lRou$^3@)JkRcsYR<0uB%Mqz!4qKJNY4eJMw;Q#T* zzx89qi$jHAp(1pDs~!4)!Ms1|@XB{zT1uOoGSMI!;SRRlX)$E3G{_cmXT|HgEyMhi z@}d%+-|sj^UTP7dP?zKCH+AARPy--*-erb`8qXX!N}ReLLTC^(9aKu8k@(>{i&gc} zwzcx<{6?otv=o)1IQL6w)TUG(Dhgv*n|F-Kbsn@W)GP{Xp$;Iuyi+I;@%=u#%tAk2 zNlZWU1L#Dto3GK*6KmLJ^~P%l#rYvV&o&;B@YD_3 zQK}CE0vcbo*#qJ(j_j3YHs$hlMpAy$l)A?;iy!Tm9>A&nQTs!;MU`x+Pwic-@&4%v z`=6GuT-OGkIS}#Uzt@goDlA^px;NA}FtDVi$|bPh;E4Z750u>h*_ig_izLY3>0gba zP&qUSC{_g$8jvWj4bldyrYV6*v|9Y8S5qR0YFQy!Pzr<|t|vTQIk#J1H+rRg2S?ux z?40X|_WSi|utX=8o$K%K?=pzIw$a`*@+GlKIOcIac$r9bo)|kDC1z3si!@{mMIyL1 z{u8rJB94M&gn=p$-I`$RC#qZe?6{W1A|T&5NFVh!Qi9nRIhjc{M3@gNB07Nym#Jk44sCpBm4m$XH4FZBu- zNL?5u^3#2TD+|wPN615z!xTjaqPg`guUZTpKtBa$h25}4DvoeA4i zfD|hF)|DS^+ivFQ(sjTZlVP1W0F3M}c)%hGLQZBDT^U@5E(80~)=Wh@dlCitGVe3N z87?i+-Bi~k#|`L+QnwVM2Hjhd^=zOMif4tyyX||qLZgGe?Uon7@ujA#$5%nkoh~?* z8qKP-S6l2Y#M2>^6szN1>c!*cyKr@v*2eYIu?2HUwe0)w7X zfSm#24>zxTK~m-ou?lPSD_%W6KG-Z#AtI`2#SGl1ogmZMT2$Q>pi(Q$!0x&g zC0A_~{(9Lfl@#MU6iPs$o!lU@*g(*%_pwQZY793g=laj-eKmmF%upipqzi+Mr|a9d zjrvlj33%!STg?aYgSul{r8zlDKYJI>f`m8M6%;dp9m_n7^yc`5I?4zdxihy z**=OoL@*>aCKh*q(;cyMt&DLS&^cE7OPghFFmEfF!h}2dIvhnUubEs;jk5h4DIMt$ ziY6z+tgayp)z3DBT%8URW}QFj$+goJn22pTnB@hy6N|2ut>w!_v8yAo-WI$FwVI_U)6!af z95w?L9A)95$>rKZK)G+`0v*{|o10l()1*>BAy!|^zL(*4(`M-?x2n|@|8j1i9803H zfS}g$A1pX69`$OD6S?w4rFj*5B!snZtyOAOX-NC&CnJ0cjeEn zB8?v!K?l+5z5G8TXFSaNmdVdG5?BI?ae6&>mr6!F5UWQOuc1U-#+~FA*$Hq@|NJau zy)YK(EsA8Y8C??c-~P=Y zAz-i~P;)XwEicxO(4E)pd>|nr>NcSaTeek?w7u`pQ**_{w(kak9ne{W1N=5lls6ycI~%6}dEH-2PzU z@eOMiuVaiUK(G4F4*65$%Ns8)r5wtdw_Qq%`Zp`(%is|%s`SJ)`*ofDFLP%3#BEk8 zA9FWBH?-r=B|->Sq>)#K zI{V})JNeB6Lp5S9G5P@$Lx$I|K4aBe&UyMbQpiD%D18_JGY3d@*l^sP>TS($fUns* zyi}+GuC32kE=f6-eN@f(CPUvZc(f2b)^7VDufeZjgNO{pg_VWF-@@kfC1Ea*3wCnY zXU~BQXo&UrgS=ceV_e+h1cP!b=?>}lXP7!R*vuD11HMvBt^>4;q8_SxyNm+L ztoo~XyS)LJ(fGIp|JR@g|4{^{S72v-CK^u4G4fH2k(ZhqETS37?oAHAcl3ncVcj9Y z@ufP`J9ungc=T5)7X%}+=t)--1Eg3JWf9J3CKp-KVsfCf6%X+cBxMWtFH0Te)+cT= zc7RW*p<16hLg0*Be>33;)NP6)ksyWS)W_*{%!gULQof}k285&@_420Xj;Ta zrzT3eCvYk9e8nj_S0Gi(G!&zw%wS2MsyJm{&4K_d98o9^;5D2<_`!uRHhbvbk@DcDoML}Y)>}XYTzis?XVtt@_4!TIiQVe zSn-H3LP#GLqS>k(oO?l+#W~&H0V2d9#j3vUw>Sp|0*2#2HyDA5B*3FXnShfpo67-H zpYGKjA@Pb~{reM%?<7mjuR5R@#OU9N?#Jdq2WHW&&R2WG_rJApaiqDuT!a@3WBd23 zhC=VvrV2@Qf!U|`M!06)fd)%`3;>z0JsO-`QVpCSdV6z2vFAqZ(XQ$tx5%Qf^?EE< zv<9VBl)lueg-tXTf|DZ2H#Bs2tuOe4^0|Hq+=LFoK35?H`~c|Q36A4w zy-XJmqDe)gaEWAiH8H&*_#WrJABKJxyK|4f+eX)N&6@&|%r%g2u;QVFE59Lkkpnz%=_)x_ujkfB1<6q zBDbI)GIwB>?~=rFE=v4L`0^Fzp*eS2dSc}jD<}Vr_IP3 zHIj{}+yi1t-7aKt!s|NB7AB|KmboKO2F|UbNC`b6IvJ=76=uFiiEM*Raia8LMN4hd zVS+mxROj;EEt+!;G!WXKN3}i!8~jC4K8k(IAqhC5l7sh8lj}ku=XsG zqQgAtnKRb$&e&CCRkm4m0JnclEwqMa8d9HNhU{IkQK}z+<@ZXTdlp4 zi-4}jz9Oz<9_j!(r>7Mg#}@G#o623bO*sphpGVl11ZDWm6C1L_d=YuV+GVEsVmcS3 z`whDsLlm}`ZN1bm1XbvD(W6og_KWDgQS%XV!{53F7O+h;mqr~CqoM-m3a^biJrcG@ z)TTdQ4PmESMfa8QBEHLOSN1NgzFG(669A5klYOTfK)O@rAQl7{Jctd0yL3d`dIu9( z-R2jUpWcCqU_aX?LkPID?>;U}08w~{{{H+r50iKO;-@MCJHL~oCAII<+ZopYBV1BQ zj34S*N_h+VIz#c2OFdfy_ao&G6>AukG3GFIbF~Mh?1PDN`4rSoTz(nZXE3eDGl0d` zrpP1?out{FkS(Nb>Y&99X*_>S-SCp|s1+b*A9if4(dI9#$w{ zB;ygrDV@tM3}zL&eolzlPnV&n%H#F?jeakc&W4$97c`nRp?p9+E8q_O4!5OW#4dZf zp#EKm`S+n%;QJAeqyL8JF58i)c2l`VdVyqsb@YgTZ zZ=YB@xzVu1GBm)@aK1o_5>Aeb@#OqY3z#}Fm#Q7fhusOp=d$CNw$Qoy(ivL41;_7B zVs`}mV>U6#fA})da=7;7dAExqh*^k%_9v>Z`yM0Nu}^fPUk<7d)1D02av0_7*Ub>~ z!f&k(jNV)|0Z4AR`$*WaV89i}NSIXA!_;88K=!%xT@O6eY@!+_xPQMH;{;FlW+37n z`QeD?G)elL8lrR4N{kr95Lm+~mQAYr=!?4Wok%P|*bUEZs)_9JqC^4%Y17_))yT)Ls-=XiFWA^;Jpu~&T{%3^a*se)COXDF@xj^eS)aD!Bf6u7L0cG!rf=8MM&DqCK$UH)V69$8dxkkh{5Fv8XmN_dn&Dju}-;|NlBsW?P6ifp)u_rj*6#VfLZOz|O-Z(e0>)rpz4M64H5vW<8x2jO`tE}|v&Jac z!jMxY@ly9P5q~FgV1qhE03Z|MkJoR$c^>=+*@ZSoU|9EHHxvkO9$yl(DXksPF zBOhh7yQ~MhRwI9Qq;=$Q;R}uv!NO;wnN5wtYB%>5960PA@QRFiqhLU#w)gltgAC;N z=>H*mCU%NA{@rc=`JE*7hb2fDnL_{wmNw=MG-}a(gPfs-!nc*f&ZDAO>Q9cfK)+_y zIffbA%7h=xgxBwj!f#5mU}t>(w=&DT%vPFd@$>8sUe}yEFEhL+GA~0mk-j9x#*hXS zO5rqP^szFg|4C`?HE`*t%QkeYe$GH{ncuftT~VEJTun!qUX4C2VF21Z0QRm!Ba?W+ zk~@+OQmS~XmWb}sgcm%1%VedNncv!F%23zDWCB;*Lw~q}==2=lI%|@s>7?(`RqRlvYy;WguCGoq{P_(>? z*DBF-xJjqRu?yvA5juPo14K7NCA{R0#JWVskG}L?gkts0+RS5)oGATn+?!0?hnFf? zxC*Vcu-z=3_h>u2f8OY}wN?8@w@b;){EhCIGik^6WofjAmvN-v60v~cL>SE|*k-^~ zyJRYBMRo1s`_`KS4V5f#$qvVF6BfuW@XVA)sHF4EB(VaRv4vn_Y6!`NQaNm&+Q7Ud+hSt z6Hsg?x|vkuyrb5b!v7OHc067KL~E!QY&NGQvnahPP6MAXWUMIq#Xb=-kHM^vCXbuL zeU2i99ufIQ(FBAy{Ef{*IAbZ=ENcrb&~K{4Vbt|6s6+aMa4;}m{^_ZB#2ha{@QnXn zpEWbk-zaQp6_w~?U;jt;nFMlx0H*G9#3<(sJTA#Mi*L zo5Y$aHn7`av{ZUKY2!K}yM`DZp}Myi@w(==Bv*zPF*hRmk=X#7jnaB2@Yfu_YF?D4 zsU~Ee%-qzz_SQw!(VSN4Sg8QYMLkj%bqzZoF*>$$^1k0WWBlKLaqiaGyJ}ypHP?gr%sFlH z=w7D`h)gn$yGzO5@swf@pQyh%lS|b_u^`ah|z|1O~^MQ_xLe!vOh`!3?w`( zN1!-qZ`4jk2%`Ypz6-Si`-^t)6HLpag0o%(PUa$+HU#K$rwef=Qha=ORo4H^$V&=y zn5lHliX-5b<+Oy1%tNl4UL5RwLyZj!*4MK0=Ta+OpoeD0*=2uCshBwih<~asd%IAy zPq}?$0;x_&hECjK{29KrRRqC!j0-DelBH3RuCd;N1vC#p%>4eWDT(qE6S%%k0fS+MB_F4p85?JDoi=>dB!pu{`6iSPku^xWb zT5f0(d_ey1`liFf+a-vB`M(>H830MuoXZR@00vksMZ;HWi&!*HtY3f)(bBI}^DOw= zz$3R@b%bF2;sU3_Q@?4L%2TPe;oMe5&0$KID%3K)3B2-dp|tMmcW>R=brY$6sxsx2 zux!|MuGc)w%7upGSH9vBVP?0HWaV1@oI$!pDDPi4QlJ%ba;M{>LJNXCGV#M@*kO_N zx&{C!bOZ8s7?#+gcD_$Ky7u5(w@`T!msjN$=0&*z@5ZY`5e!B8`F!$r_-SyrdJH%aPPY?HUbRzlN|DxCAm|Ck{q%E9ccEb1O2Wwbt_Ha@{S$iFT8O2u}r7~{W zW{%|d+vLA21!A*&>Ps}G*Mzlt`@J@>j{&|tYI@jY5?`JtvF#lP1Zck`Rl{~qeOR*S5c{}gLjoD(;+ZEw+IFVjY_?*C!A-Nf5C znfRzFz#ZaoJcTyVq5};0RqYiq9~M(B)=F1ZZ5#h z_Z{=F!o=CXBF||W#5#G8no7ZAC~DT&s*Z0zgAM#BaMpkO zP-lK%#Bb->MTh3>P4G7mGE36s)4XDD4zKDv*d3lWVoC54-FT!@vC0P-6kXDWC0s%o zos!D@!Bjf^v1y*Jp>$3ZV>7)hgnt9DM!kfnJzx%T4jShGx zXB0dMo-lqOdJzj$q7)W0d`A^6lBDSsRTvlis}Dly2yGRVMcO~Qrs$P)a?Z9>SUy%_ zCmlp(J{|pjA$o9N1%{+H^na(h$s8&|gkNc{#}`H#d;@8*f9*mx(ASQ{0r|syhX-go zuZyC8EOD+z%t6gJq&7fG!AylvL6z9;#sOQX*&Q>LG6Y3>b;rM2fhjtYa#jW&27j}b zyKeeund00GfP_7kV~M;`@?eEDy;hLgQ0v{nbr_YXDThazi@UNoymGl=xnD<_b{>v~?z zS?)zUiLAvW)30lCH9X9T{T-(~pEYwTUbRb;@t<2f$ht86kS=DK1uDXPXPW`f9l!)&2u!K-t)@(9!g}OHod9X9tKWS$4=dK zIT0G3VcBijqn|b{*cFx&M{W0AjW{0D<$5#6P~&17Yf%5{N}m&=TD%QU?(&MSiU?Q| z{yxZX2D&N^)TW~P6Sd} zarO4}J0}!K{5|l^SJJ#!8-IL4sGP7zzgDwXGFiE5r^>|`ef~C>%KgYylKTg%ZUU!c zcHdwFYN49x*Dk}@UzhZ*x~HiG+dcJn=gbJZ-}#WS$fEt81^}*7=_p$CGg2Kq?AOR$ z;eWmyvbKqz*e!j2$rs45n&5%0_CjjW+FI)jIDdHs^xYE3cay+`oAF=M2MQ3mc(c$D z5WOMCgO4E9aN`hQlPG%nYZ8w^V`m~gF+zt1)%JkN`36MR_BdR9D>)L`HlV_c;CKA! zBNY`utYiFqN&~PZ&QkIX?yKt|f8W3+fv_Vy+J9{!Yi1$`gmFESzNEfjdnQEQP*RQN zc=p&Mx0nVBL|`4SOBXpJFrw~L51equ`1^0cN=u-b^zvFJocUz4i6sy+#`D5_+AEOD z)ax_RAO)~+&yV)wPxkRj;FyMnBf#1xNdz3&tpB~759E~iYihqvo9&wb2Q6jmKL+Y! zRe?}VMGUbthkK5D5|$Ctj`)u@>i^jXcaPId=W0vL+rtG_Zb4%KoZx%?MJv`w z0>zY6PT+rJ5Yv&hJGuuQGWy&j`KS;s-1H({70`KeP=iH+R6Hc*-M!@8b1qgt-j9wL zzum4V%!V*y;0}>st1}09KqR8bl%@{JQ2sPh!@Y+&L?=V%Rk}(g?yy=-$uYBtl)qqZ zFwYD$I3Cq%TB%Aw3eGqJK$F)E)WwWSdv7!rZZS2z{!SU5d5wDAsOgMg@*Vco+-2Wk zu>jh_b1LsWYJM>pI+iOs~|&;FC&#vQj&QDsQc`ks;f*~+f6wUnBMP$&HEk$p&a)?7Iml#CwaxhlQi`^`F3%TTFT z$7f!-fYD2}*b6!eJ@EeNaBRo=8EY!aHGd3Y$AfDvvA#s3^JV&x z#|gMp#|AeWe8;N+rh|FaM5Tt1)R5)4a~ktCF(qu;SbXl4yD0ZwkEiD0#5A-s(i;q? zJkZ0vGP)-dO7)-f%i8CNB5mw2KnAG&!N2pf5&@AdwLxeNIiVWVKxN4-DPCuM$|J0QjNIq?f+$_k7KWYG*aq%3 zE1$4KVaLt@AhG5dy>qFswRnPFD={WO#EB`}&h-&}R2P*}&0G+E$L zpt3?mafJjZvWEz{CUb1yqMmZAEy~1As_+?+;(6lsoD=o4K{1OykIyq@t-&De6X0GJ zn6!rndo4*OHFcr{Y~aKJgWURwHNbZk0=tU8It=sEj0&OKl<9Ql zxck(o&&%@;sXxvJQ?7BJe?YiiCdZd_*<$>unAR|t34#f8si9O*sbM;?-=ZUdXBKh# zm%)t@yq*{n0stLfoz8Y~ypQq5DVi+^a{90l^^t(QIhncj0s?`wxn(~Ek1d#<@6#`u zGejTtUreP9YRW%2K;BT0VBC2@;Q8XDfwS91`18W8HHM;Nq2|`w23a3%2XTl!_r3U} ziX0ZNyY^EdoSJiaYue<6p*H7^{WcKcxOWm0paw3V<>})AVv74or?t+B&@em$PM; z#{ME?_10C>hSXNwT$V0T+(unehgCB>7qC=LSM=N~NC>HeejAf~hm|SPWc0l(E^nio zq_xu%#3?+&o@uTj;~HtmQ0+zFDgORdq{a%WMa6VjS40$OYu;Ia+CGFOo0*G zWJkn81+X<^p|u2$v&BYMxtJ*T+k97#TXtX%u+Dwtg-af;01=>*7i+i_B1@Yv2+E=dFD2$4f_Q}oC&be<`ZAl3fZq4kUZ=`ScSL}(^ zw$U{am2KEH-Eg?UUk?`LtNQdfl&rg*dldOp1Kf|InD(3K0}V*rJ=4|BJeObFXxpc1 zwhM;U+Jg7)#IbXEPe#K?@>3EDeaX_kMzph?FOfZEWgx&^hLV*&qsXqqQ@|efh!lY$ z*jD;}LTf+s6VrMv<~$--q%%n#=)I~2fW|@BO?H0~*~nvJI)B?As-_0Pu@o}=)1N5; z00zO{@rLd%M~(&ha#`;#zs3Az@@2-zC(v{3FEl3R3@k{h*%c3uG@`qkWRXn1_uv`l z%8z#ox4A?O)q?6azC$*m?6am6c~wq=4~s>K(L_K^8BWry10he6V5u|OVmfn%0{*X- zigAc(T=y6GNgnp=Oi&&`3w>P>fKz%9j}SO4NpNwDH0~}LQ9k!fs*3?ymFb|WjkI_I z_-G(Tf4U(g-KqbUUgcRYs~$Z_-<>UkST?HrPcp%(ou?b&M}hWR;TOb0%s51 zduDWqUH7g>V#T42P3lEEQKXQIn3t2HhG6 z_>(yDT8}UuWUR=>DT1|Rqo{D?g=gme{8QZ#ml{}j0O4k!-4#Kircz-P{ib{kr>B~? z#}1T!4^AMF9F41~+U1r)RBjEOBAGY)}KK26>LT{F$~qSfdDvj^2H7qx5N!(C;)OGfKlTT^&!UW#3zg{F%FgR2>{Jvf5!(z)vrGS(&b8rHLL&{ zB|nE=SX?wb8YIB{-{67!`ph(+K*wiylLLVoqR(*l1jJ|ijigKe@yEX-kB+(D2&oZr z;@(OVU`T7hLymc;_P!halKw=K|0@|GlyWS_E2g;jyL_==F{nT_LWMIT5RZ}ozO`hO z0o4g@K4uIT?xy9%KD=|OLz|4sk%PM`?@ za%e)xA5HFe$Bu8vqAG%dD6imLWvaa-%xcWZfw0J^@6gTe)?8klwC?H%UE%h5;eoRQ z|KYb zoN2O-;SMoOFgA?h%68)noA$#5t2F^JOuQf5Grl_nF!BN;7bea;c$&WF%cEt#CRhhR zbi;5dIKadrKEEE<3?2+$)+@S_1bJK55y)k9gm?13N=_@&9oy?V*@WH%YX|QPZ?zVC z*aL&*8yw)zTYoHqZic8Ha={`J8K}zRUwyPI8;_8>Ycx1^vXABPk*_a!%k=K3y?4_>4DpBX_?}Nlox22d{_?d~5)QC80w#Nub4cJB~v^+t9yChsVY@ z>NB_kT%g8gR1dA12lpDkowKZ=0oxsE$=?`YdrL_kmM_8yU>YBoYD%LqQxo=@R|SUX zNoUy-p$Lqw2WS8T5+8l^wjzIC%bIZ|dkkPN1euu2~?NabH>Cc{mFCHs;XA~CuH>pU^8aXDl)$|3S45{mjp^i3C( zEtsN~D=E(`S_d!tZORxTObyF1e1TbK$U^#D+ePsfym*d~*f->jgmuL=_=!1*)TLWQ zo|~1!FIbfNmcQ;e_!LLHP*q0ap9G3(Tj@UMBKi=M9Qw{F90iF;F_R>1_@M$?1`$M& z`+jfZv4AXQ5S0;(_I*u-(l0Xyp6sXpE0!0glpO`3Nc>NkDg}}VgoG`_2or%KzrFBqU-N;Gnh5Xg8?ci1A|$>GRkB_ znf?m0^o~N*a;|p?=@+Pn(@WToZ|nLNS6%o@Ak*j$svZuXy`R@lcjY*LJpDV`2D{sn z7Vwz?PZd=f!oX1m)9Gn{%Q(a!^+%tRZ3#}JnAj~2loQwzp%CnT1TS=mY_y{ds{uUy z2tq=4VIE<5QV?n;q&URhN55lAH8-F>Hm&I~Pz)IIzF?`r5XGTm{;Dj1W^#wk_u7K} z?da26p--S`Qy|!Pex=}zXA~u-do66^qkEdU;Mo;E2J0|c}p{8mzc2mg-Pqcks+A(XlIvm#-Fac2cw50gf z?(&+h=C8*j(_tObaoSEDNRq&VN+Dra3#r_*u!%5CeofY=Nnhu z*}vr&W76q)PjM|8kGR>`YxFhx8cE}~81HCayy>#FcC@+%WMM5=>44troZ}u=Umq6XoUT8Rrt0|>46L(IGeHOHo>$sS;}l29kZM!Goo7;w2#>bn@(AX9{T3E7Fs?4=_2`A;J1Zg$T- zAp5vy#4=mf-=a{ey{w^K%Db$gS*npHnnf%Q32ep-7>mCH^>hsdMYKbccPsh~uR>&- zdqI6lh>~zc@s2mRwp=I>_9gNta2m{pd?%KjyF=|$q2K)blOFI=zOIEm#9k{G8uekb z!*NQ@naek~*cCn`F)bgLBY3hJnA6r2BFJY~b-987w~1KS8BW0~gx3`Op4cGA;h?)e zf^V)Fo4Ud!zO{#4Jyd~mV1Y{_ApBw8(tQEfoM$E1yWUdUsd*Eh)GYuAU_`Sis}|f8 zyrqcY6^}%2d;!q>(n5m_Io1$?9JbC!6LzVq4Fo~_XI{TGko9{r>_(N!Rb7ucq+d}o zM~7Cuquj_;^IY+=Rb7nQ0cV1eAiX%y2nH9&$-8f4W=L5asIne~pvh-#va-ZQLiUg8 zr-;_Jr6VOf))Un575(+L;?Oo}0AXA&>54`Pd|hDmAG)H(K8mZDTr`;Q!v#fer51^P zH(1Dyt>aI;|DB|@858G%rWF5Mt%!c50tqUCLx0yA07)u=D+6*-tEE;B23R)!_Bm~g zm~*!F%Qpgf#srtw0p2U$~W)&2aYD@=P>5>3c}x zd{|gPsfv@|G5d~#D}C0qEo-s_ATa@T_!yUnb*&*g*r?bwp{|<(ALgDKJVIdTpuy$7 z6s5k+t*eeW$Y>}D8=O{*Wy`?BxoVMTHnM)46%gZ=5`J<>VOl?jgCinxkrNz~=UHVY zOLF_RfGQqgl!C8}iLXB$Sy#cUbU3Cp#8@k{RVYh;h-3*IeXKXI06c2Gvfo;BPlG2jH-z+x>+B=%${a)Na4#E9Y+x|^a}3G-Wk^dJ!tqQphRU0cHzJmuc(ARG z08sivEeVZ&7y`88RiH-t44Pd6URYyILk(iUFi&e;Y>5K(_#@Ax3 zV@FJTQ;&F{$2wa71l3|kKJ-XbrJ?r0kOIadmlQ@1-xBBwm02;V=Vj z+A*RyVVynd0n0ev^5ZVkBJHS2-qh>i93ZD_4-AbCR>xj?8~-85m~|Zo0UJefk&Vv? zAZSgJ5M@8MZI01%hwm&xJ5AO?#Rv;>zceG4GfIiFg|DzJt|IsH0MBplMk;24eDD=u+d7Gai7L2YZuu$Dg0$woY z89f3(rAwLRx<_z31$9AS+3>2MpIWr_Idj7|p91ZRKwmJ;Bwi5G zm3vGAb#wc?D6?&)_EOnrwWcdluO_}blIIvueMUvsWju17Oc-(x6Hj+F2gqLez?Sn7 zzLi&$Di>ZWAidgA5}as(gAXs%P7p_((5dMa@+Ro7NsjKBV){NBxaR<2GYD_%8d@`J z%oBhJI#mPL1R&PT1DJg~^q|5?C)ef!XmsS3u2#iuP?y|@1bw)S)MQy{Ev-ZmtwyJ~ z^T#wlCIFDrWr}O=zUyD|a@p_Gb zK^A}O$q~TXhxr4)1Hu3Ntrr&GkOoiqjoS-}pc?c2H{jZkj==$4LqGH^e(d+(+T4@q zZhCLs{1m~SvoQ0j);)E z$gOoKvb-djBCBx-@l{$oyTmBmk*U!kCK3>{Qor;>SVPvtwf;HKPo9zd3d#TRwDoYN zM|*zFgwg8;#Sd$X+LsLS)d1J~FCWTMB)Jd7|NdXk6M9W>ZfLNfW={6+h{ym4EJRT| z5#CvkO%qpjiTdMn62RFYZqLJZBv{2%8yvlT1&R(JmKJ~Hw`UijZ;nT7$cRBQdcy%Goi++V?861V^oM{s4UZV_%kLwQaKS85 z%45Ar>aWZU`$d34uA6aaA3LpS);M=-ABqpe{2+QRP2B8gpO~SeKC&pJJP~Go1pm|? z|GmVf-O4yWcoWQI-tUKhevYgJ`fG!;kTXeuLrD{jL)D>-#0vtdpb+8(v!V9wsaFF{ z9ku*-WJU%Yn6Yah>he&5y?IQSDfxb?H3D=&nhJ>Uc~J3M8b3mN;}xLkX9Poyt4NAi z2@EyGhs5U;1uIr8+K?1zIiSvmkGrs^o8#kMDiW>mwG28M7z<6!M?Y=gWqZ2ck3}0$ z*P!J@Ut8j0XxjitKuq`kn%}v(UbF}~yiPn(se|NNJ?(~MYbKG&x@xw_BjUXH8#7^I z)paV_c>}*_VhciC5{f2%Nh?N_hR%^_MS0#5C#D!g6?BYxE152QQ{lo5;mlhxcFP+} z0xMN&qf`|~62u^cdn{N<(fz~XDp)2{FmJ1RAp~nFfkXw^`thoA8O$85-J7}r{yMd* zZFuI(WJept_?NV~FPNYv2fodauN6C-^{@wWv0!M?UtaPJ z#j9^^0$GOC9{!cN@WpfBbdb&pCuw(rNoj))S7hCf7e0qAL#dD<-r)qYlp2Uf=Uk<+TYGUOY)2*6w9+R8wceb|i>Y`Ik zZZ0BZ*j{F?%I-(l48!%s4vi6Z5rLELI+G|5*)@%wqm`p4mC2IlwWfH39jFxI%hmCX#zXm38!Is$I5mCQQ~CEww`cTU|fzzPR>s9)xBL(h{G&L-=znSgMG&a@*xG zQ?F~1>NXRlY86D=0Fc7A2m73^)ze26JKt*6E@2sfFC10bx&Bm!fMGtbGPMzgR{yq{X*@=xoWwev^G2tbaFG zT;BdV;G4TrqgASH+A>Ekzjh+Lc_5!B1J+R1C!v+jp(VywTEkjX77)a6hmHq-x$3X)@)%>!eM39QRkG7;m$58vl0g?aT3^n`KcIR zVZRUMwy7PUA8}15?!)4!Xi@+jott{U|Os}OO1rnw{N zTMs&NL7nax^=^XreGgD4Q^X{S&O;^Uh#G{T%zvaytT2SO8u(AOgo?kP`uVr+K_7}% zgicxLHE#q90&VuMp`@sP*I^kw!iHlFk`>`U$ zpu-#)^u9xH6V29|^7Z7i8jn*tf)AEG$aGzn#(t>%7b|x0_|-Sv7@Vn5^diNmuW9oH zgjow%Lx^KOHV(iCuFV_9msFe%p@87=w_&|G(QhRu0{NJ-acks0as~6QI4`}0{@DFulA8|P(`vh+C@iYmAF(rcogYM`ns z-eu~tTmu?C1?*O0zEnu&R3WwG9>)@02yNuKD_F%g)@K8hvHR~=Da5}OU@PB(?eYnI zF5Ek$ZK0k+`ATNwaURdv0n?%ID{NhTH>cHRMF&p>HiNQ!-*{M$w- z+5|p;xN+C#G9L64kp0&Xxiy8#7l!yZ>_iz=^xr0|qR>i%Ud)=s9|q1Q-9Ox*-C<3- z4pb%-4RDkI5o%g#npYEaO>LW2hmz3E|ID}p80U_Evgiq#b!7br_Op*1na8|aa-RR? zEwJ0g2zBXCY%B>G&QTT513HEn-Ja3Dt3(plEBO4nQHPO`U(o_UW8v;K1rW7`{y+bc zm~<)g34?8KbG;J&@67n*=}_4U@{1evf57oq-;BZ7#?aZhNX=Fq?Kip~#TPt_78?1U zz*jZ^v2+y&Kt!qu{-r`BLg+JdlK+43jPU;h&nB-9-(&m!1J61TL0|Cf_+NO2%?8#2 z{s*7w0+0S*eEttSdjjX-AAc4$Wz$ugB$S$Xxze`Rb;L~-VvDmtmglQhU~SM@b{t+{ zd+BNKW5hRB+HN8{0<$$Y7dE+odwKPv^KWxR@PQt)}~V4Myuk? zCBfIV>_CM+8aN;t&YTB8qkKQ4bLn2bkIzR(8|-+@9>-1X^hjpbHOj( zKmSj=R+k#Xd?c3VB6*@$k(C8}2VEW1HrhkVZ^QKCpUP4QXu5HxF#GigSjNWuQr7tn z^f(}$d*L)<>_j`LNbcF?xBSF?3_Vn?ax<)8IQfP@WHAX$GHwNc=^hL7(aF8?K4jH# zH?)pJWGOb=^gcQ4FXE`!EvLSkmso0yU7GX;nFmjH?U@qkhLL(|m6|H^(rKPus`O~- zEcno#->h_6)x`zMW3N%aRgqotj#M+RWeL11NFam-a;6N9)i8~La$VG9meJ@$bu6-h zx|hy7Hq)=yy;Tk1>?)#N)iw}^XE{&450+&jY+q3barz@|XFVA=q=ID0<#!4Gs8a?@ z;?yVKe1i^y?JQ=FI)vY%hw>l33LKyeO<>E;kz5MaSYL9yR0h{hTbriS!Zoj|Dl1D; z+ldD&!aQNn@XRGleG3_WC`as0n|&M_&qmf!jD$vVnW+*$6upGFQ}Bj&6dsYQfAOLg z+l)W37f55Z4#lYWV#}m+(?2r$?(j!#U|y+l+R}&h>0r!TwXSGBv6#lM#^yp5uV}v7 zg{{|Y_z0$&u>>S@v1Fsv>10A!Smk7Vb8I($&=qp+4_V5b%aa7j9&}TCp$}?IZUU-W zmKfnVt?&S}nL2)8mR4)bkRPXsybPPBNg0MwH7Q2yk^!-+o-^G;1aag|;H%WL@}Ce& z_P2lZhmba)x2hoRiJ_ZfBj~>al#2;$+=iHF6jN*Z{)k_rs`R{Ys#;6W?mLG|bK!jk zr;IWAC6(zd!v)=3FZ~7?OGT1$+R{Lg?=Y~Za0COCyZAa}LvD5&x38_#Pj;<#+`Dhe zi$k**lF9gLO<1U*`$HcHtzz?)Tuc9DM!VW623hsR?K@S;7NyUH=a7=7}*K5RqbdjG0M2DblYdcd16>%7;nf>*^+T_G-DD5?FhBuvt}kz zOBDdXyr}jhSY!&wgHduHubu|*YQmRcIz$|NjR^C6@x8^+z%q+J!?f5Wtw2{?(Q?bl zUxWlOcJ9zyh|w#^uDjgo0+6`iC(m645(2^*>DzC#n%}ar)HN2qY0%=-(barmu=ldl zk0^8yzouo9QKp>doTbN`n%!)Z&>@?52^EOw zJu7~}4$709wx101+WDJ>jFzl-n4RYy;h1uH6nZeYRWons(ftW)s$wqa%Wpm%+r7h< zO7ViMEj!ThC*K^ubR(HIABg;NDLt@7o5-aIg+~uID4TK2?F6lpbTAZ;4KSMUL= z)j^wseBaaTxiFm3HGqZr$x3FJysVLxcFpOYYrW@fX>xxf+1g?ou;Os+OThEC*GXc!vESE<1L?ZF4U@O#FB7|Eyjj!6|9}y8>waf6rQ4 zz_tJ9nPVtS^8fs<>HwUB9_H&Ga?=EX0w4o>2;pW1Gzh8xdFzbauh_g<+a4nR`+uW!gTB?{eb#T^-aT}vBob?6Xu)oQ0+SOl?If4l=G#CW07=}j<3~H{> zFw_nd?XvjkOvTbVfepB(v;g!rdi3r0DLB)NO33Xnn;oVvHB@eNl{eCx6FmQR*b`62lf2CiKKa{ zevV-pUT@O9tXYQp8VLyeY%-`jt{WiTRg~tX_<7U}-s-&UfYu5iVF+6J4Hx1_;sHVUElAagv zvkq?_xTL#odg`S9=*a=>5A(b|B|>8CPNzIYK9y5{m+_Z{+h zTD`x+))3-w%2MzhO0!pUL`*ECXgO>}mc3AElHem1GH;d?{DZ2PoMTOe^skzA-S|EF z&UH1iKN|k}q-BspkM_Qe>a<(CriRb^?4@qKbO2zG_NE5`6uRKmMR| z)oz4w*cba#08sYqNGA}pH*ACorVW_xEm~jHY~! z6C!{Zr(L4z;G}Xqg>po(n0GempRA`62QN|Qn}+!))T%|VNZn`>zg+_{R?vx8xp`Jk2T_J$XJEB;9P=KHm?vfhZk zo5mHeBWxSJTi0e(dcWwcWg-creFNu7?z~6ix87S>b*Q#{wceQ05o4%3%(orC?A(r5 zcMyF;0Z_hRJDAkG!F(ow=TF);)ofc#XdYdEzUE^nXC_|_{2aT?xRHbBPjpYav4ii5 zYsY>=s@q38uuB0FUN3voJsW#glV2u!%XoH&B&Y;yw1EhbG-{OiEyhA+aGIEu-Lz84 zAJd$=sR^5AQgksN5@SirxYKt4-)0BvB0ZzYJla~GJWRA zsWuV7bc|Ex*&06bz@CmS-ah@Nx!7mCZ}i3;Q!d^<32Zg)d*AqG-)zf1BW0gLf1P!K{j|%yG`|67zu==M zdFc=7kBkx@|B|O#@=sEM9h}c3%4dCPKN^9(6W=K`-x$gVNcrm{wp`W_M$cn+oabt~ z=SJQUXU{|jbpvXZz>*t|ysE;Gc~}5I?7^&=WyGNzK{+jrW?n^e^_Udx8&8rLNp792 zsd<@ST3L69pCb>BC3}wwS23!2oo>ayF%+mqj$q8!puB^v=r_fKM|MtPk4%P1J*%~g^_eqkgyd5I&1t+e zAI+NYR$T1M!jo{uciCBHRPJA{3#8sb?veJE_3rJ}Sy$;bEzC1YZOq6kD`&Jt%PE4^ zmIcj@iLr4v94Jm0Zy{}_i_e@*ULpkN{K4gOr)=Ji<%}w8yY~0&P2QZrQbAo0m0b^W zmC8%JMh8NZ$&oy;42BIQ9~^W3xRHP!vFqVr3us0&s*7)N$5DOP z^!nVc{YNq0L|J0^*gTC1IkbdI}xC-=ht9Z*hZPXI`uBP zaO{#ShjPqA^nnxAC^_Puwf#K@qs0$4JK}k?8|F|d;3U@_qKtq`b4>=&E|M~$JYlXKBJSl2f>VLz6M{nosFAcT)J~L zX+CsZB+7_+nUR5h%82ZXOzFhT(I$oOMkiGUu zOw~hVeX$Lw@%6KwH~JisCEi6sqye8WXeaJfLpWD`JvaDmT)>F!f-&#ZZFg+Ju}Ec< z5fd!on}COhSTnaR_wrZ5orZR07S&odZw1Pp6p@>OV5RV5tEuVmyh`b1l}IOJ>})7( z2*r)&7SG(ZO*35uO}a+CZdBe;w>XwU`=4#zvuP8c6-d@Nr$V`+VO-wa+CQvDZ|19E z*KuC;k7J~|!QQ+`zQ;Y2!3=g5SV1y_dovezUb@#}2O+&l{KJqVG5lE?LA|7kA18e~ zf?E7nxjd_Ma@8*&yKhxJE4J-e|DBRlK=AG=XZr`Y`(gpx6!b#!~f)txc6?4^F zPIN6GCYNPhXIXHls&cb=k?L$oH(|+6a&Y>ON#USp*rl|XnS?;xZ^7jpw7LOn96G5xMUyK!!W8n_Jx& z4sxRE6#7M-hRPMmJ4(5_i)iZ9Jg$%2xg(@`gd+CE! zSrg1ch#h1ol8yOS-$I1JFiNk-NM-U&s*il5Jk3(yNPgVJ(fqv83?>AS{>}QkVZli( zPUSiff-K9X=#piD_GT2%HP(~*u*nEeUIF9$QF0)gUIQ?;&fQ!dc#AkOHqLFVE$Ga$ zP;I+H*EfcaCD3)ETb9n+r0yM6|C)EsDz|nea5vbp6 z_w{U#c{eZ8`UhuIM4VYevRg{3SuH6F`z%NN%0-SinqB?7+M(^LPPm>uS#5F0e3E;H6}~J7`kzHlqHuBC zNTrDsh|M{QsZmtbAkIIX)?NxDL-Cr$X{T%?Bkf>h8f1E3i0Q5^S9;4VIfErj-ms|O zRmxX0Da$U?%-E;s>!_x9wu%OblEr71l#eMG&bTp+&?GT&<~1?(`sc}QeImr?4hk{f zv3_WbL!H%mF9qf88j$P{5MN@J#>K#pn7A?}M^B1w1YBDpU&1HfdO45;uXfIs=6WBk zij8KZ?|K*8urER=6ZD$>;hRCFw3ciubOK|ZW%iM?3TG?o9UXMkxO4%;fbu<9*(p7t zQi~z3<%(FS3GE)5*w{RW$st1aicvz~y$(sf+(O8!cz(kt24zX1xze`L3r1xG){rIZ z44L2Y9pS{{ujBL?1@mZ3t3Ep>qR2_IXa9qo*Ni#LWla4D^etgL0aWk!l}lWM%b$6Q>?DU2q`D8S=FT*m6yJy7Kbfx!G8}x z#$mJ1sPDwVkIO4Q3Y&*ADI;}WK+q;AGE28gsT@;jtu!m=;>hkRPZ6`MbmgWFD?MC0 zwP2rCyB)OT&S8G*k@mE zyy(bbH)va|6~)B4X%Hf!@088PgaNtS9M(Fjkdm?RJ zQ3MzchsjTslo6X3O;4Q?w)pA%SUIbh7Gbn?ORHEG7n|C|b*+s-ZBr`Cw^4RXi_sh( zikl{7Sxs$XzM<5&y1~0$XVR-4hDu(S*$zR!NmzB^Nb|kJq71 zZOWUbm_3r&ke>NN*8JZwJk|a!F+r+He%rJ?%wp$YBi!b9bea-RG??(>NBX; ztx(OPttV|sYitdq>+deyCr(b_s+$+(!}pB@Q>ZStg;9R(>KZzIrp2r7|7Y8Q=N|7U zXI%;ySFyix0Zb}A;Vn&b%HC_^*$=ME+^1CfQTjA_Y17wS%aNTtcfJHwevHJrKV4Ja zn`^&^5CT*Itc%`FFYPa(mHY~XYp105)A;w*V89pmn3ol`PsNcr9dM4~=i+4RX%0;FYT@Czufq1Z|(*vP0f>Rz4Hh7BcduAaE{?Hb>*%ffVF$?=*Vyjkh)7r>@qHF;4bk&&I!pehaw`l?PD!veyH%LSHpBaA{HrM6*Z-i$ zaLf$?XCf@AinNWy6pvIDp1P8Gj13@Oa-k-2XZ`4%VQY-w$%Pw1<$*0mIkeNnyo7Cz zw-*g-ayF;S&l*kYarS*Z)dHR6*REKtq7hzVl#(*R6nWw(QN;K8Tm`NHV&&)0ny-4c zwDamHTk+Zun=v71XB!4bXpU0q)dup@kboX%$&7kl%J=R+(R3}z$U=FM5XNK zKYI&4qAucWz3L@sq$x=oalTFsHC=>`~Lm zLfe_QD|Z8x^5JXZGj2A(}@t#)TJ3Bv1SO7NXjbc(jVPDw!6T*PI(UCEZAf z47RP(Ei(;pDR54Z#Rk?K3KF#U22q4oIfpOq&@f%&$cS3!dQbRSe+susn)@yScAmZ^ zN_=r*1z~xQGrNxK=$qz>w1rg22AT2%y#PVqb|&;KJIR zprG`uP*aSWw!;-vvh>g%iHWrYel88DAsp(lHl__wHP&Pqw_-*q%kHqQa%PFU#r4I1 zvwn1h5SU<%sF>IgT*J;23W8VDMQ{yH7;M1p+iuLt5`gDtMF3|(en=^G-#%#S<042+0WsufHoKrh9`eU z{ABVSiWAu8g#vre4XX$Jlzw^HyH`nIew;lgVbyC?^mrS)!s2wZWX^0%#zX2~_{^a4 zW(+D7qPIc@Ho5m*Frm)CwS+=}BWT9>cvA7tO253;mOB#lI(oPsQhG@H2`qBf7V8{H z6>FANujOPz7k6gl)UzD;fs$tgEru4|m~jzeL7W<$k)q5%UFJZ`O#^jmzcXk4Cw^jj z@WKaB78D+Z&m&*LSML{wO6VNRdDu`=YH-wqQ>$GEFnjCV`OQOH7lbx=dI=9k9}W8y z!%SoLxO+*-=L)WP)`JEu@6~*Lm^Ew6vervGV2?e=HKNYc3>*ws zi00NV-Bia)$E-VKU=J!|Rx8nUvgfYWKKt&iI?t6zVn2Su*A+^-oLh@T8)S^gCE3y4 zJEze0Be1%ZkgN|)<;N%HWOx~Yz;qKrPnSb{o2Cp&u${y?ri17Ukw`^7!5*UU!$;%! zLsR@oX>x5Ee4@%5fQ{XA)m!$jXhr-+KjYC}MP9o~oE(HVk$Bb11bm@C8?V{B1|$WO z!stl~eIeDr7D~%58v``6wI`)9^G&{bckr#+pl8th<^wz0GWGB+?sYHG~ z^XbKHf4vPT{+cS?XOH=E{hQFjAKxnr3ES!VhvW>yHApI%{3VUK_>1}5X*iC~9Ld*8 zXT;fwk03pk0d>3;BGGNCj&)m|JjBs={Usk+_b{~+oC#r#mIz;y+L3o z{o5`YPpKRtCQW68SkL~r{yUkypDIe*3XG`3@F;N7j+u#*i8TywW;EQv!g7PCi5tek zZRwaNxh%JHBBrL$313y1xp$RLi}P-s;N*?t3R^r0CarQby7=bo@teuVY*_ti$9U<` zsW09?@#2ZI1`YNkeR+p7Ez!?^TxP1zymNg6+jGOQDOcJ8lS~Jd zktPHaPPXapPLAizq-$zFl>;9o`wI{mM?Bki=Cwmq?iZyHk4_VaVsBUt8OD*x@t9{S zb6LrEZQ+q^c^jk`)M+)fI(-b!u7Kmc+mqqEimG3F&CRuP`Z<=+7fVI(W2|3 zjYo~0LxXnLjLHh9hnB>%$PQGj@H2K(3>7ssHC0(1OB{8w%EiYA7mZVyIQe&SRox6% z?GvF&>=ONy$2LKTgscm?0wdA&D>61H7EFM}x59CwxL88ukL*2%UdNUN9uRlLDB~Ix z$xXu4EAftUfh<`mMB0L#Rk+{SfMXGJjE#g#M=L?g%;7~=6Jus z#9znHH$`#n|Ju9|c7Nh_w0=NKG1?fdU}HsS&h9Pj*xKDFa+$Ea`be_oItunE>|q_h{L+rD)b3>n zznUh@rPh&OArI3kcN@x@!9DupT00af@8<#w$)Ir75>LRj8GkS2e(T> zYYxYujs9a+ghWRoCn?bBv{7Q%;0d>|FsB*|I(eIw9A=0t0bads@(knLrEVe=)8j?l z1DGbpXe3sCF&HU0mHwfxsp*}Hq8Cz|uP)()MpwT6^bN(~m1ZCuJ@4*v9MtT;gYgtU30rlLYyQN9xd+k~^#ZGY+i z_nk(m%JI$(PY95gXcs+vvFh6@(v2Iawle514=^8R^Bmc&bAPzo}BSTlD<>%V1mU7bDC9H`|86 zE{ZR8>72IjMy_Y5KDvsd-dKvM?i7!>S(2XL*^^rj@_Pgep?35Xb67sqSO)*A79JgMmzvdGbBGeF@NU_H6 zx;L=Wm19@Z7AW_3z2Ry|G~+>N@T1Af3H3^dgHJ9KyRM9P%O5qxgK0lt+QvIL*#ha3CN7lK{&bQ-9TNg9XGO!`I+HXL z{u<`hJ5kOyPq0^V*lj=K^4K~yat>mchu5Llx0Gm{)JA1QY1=pkbB<$_T;Vq~!-gXq zNnxH4bd+8Owc)nm87Zp8t)o1f;cSvIGa!6z{8>-bh9r-N>H8ylnu`({@1UNyo=xKL z@GCH~SvZ4zHRVllR{^?U=U9Afc#t`sMK+3#S~G3l^V9oC|IHWxLG8>EEA{9Go17WI zG;T}!VtoQ{d4a|Mbc5Z4@Y;gjG+pv%b2XQ}|!qR#mgi|%dQcFD<#;^PqgnaA75Lp4+TN+}(sv2E9 z!lWCkKj{D!*L&B!Wr+3r*hffaTk|FphMljf&{9tV^_d2)r&Ewf2Y&VsH|ICIKxYR4 zm9?9$8ovYVpbMnpftxMMXJhWGdob-OfCRaP^&NE*a;OKklrq4=k?1dBt4<*1 zY{C(96t~l2MLVONK%{uHc)~gDdL~T=0i?jFpS&(Zx3uo31f5S-3^GfzpmW6SC+eoE zegWXmT^6kWTfu^;NG!?Un7hWGM|zCFpU?1yp|dbmT{NF>R#n~D1REZj2z4~Xe^-z7 zvcYqK2ehA=bble~Qb4!=B8NP0tf({I4eLap5};NPXnBdhy7ntU(d*vWjFKeaR5tnSYzmANVNJsl6)%)CQQw%*)f0_EhbVJy?^bo11bU_-^U zW$^jif-9BmY3RXZQx6$=GpuNu(JK=s=L%kH0$TdfI}-sg_pb%TV|Po>c^Jbpba_Tr z?U>2ITW<6K4#K&=>1~z*puR9^>^by>{@w)B<0;6n|FZ^mu&O8TvY`gPvY)94p|3pj z{p9ej*XNcCGPr=Mp{H+wj;!Nlp^S*&Dg}W>r3UCY)d(!PpJgrjZ8*_wIbol>MVAOF z`#w9+>|434eFe+?Y~zJSKvJvsRk*(E#`sA@^Cty=G-T-R>mM<%F90A!I}&7lA!!ss zibvm@Gm}9qL*G}DD$0m3F;H@eZFHkzF=&2izKgmqh{_)_nNX|NtL5dllmRYn$kidi zN2>wOrUeHjPuZ7~&|l4_9gzwG8CW-Vm~4-Rnpo&FU1E}VNYNHE7!pb)ra$1++^0OW z_L{T=29J@MJ+mf606Uzz123RVLkm4~3%!hQSD1s0Dc3R~vuR^Tyd(@HlO}5B?#z6e zV^-yE0&^_Fi;Sqf)h-mf7YD804nmrD^r@26qOx)#q3YB|OiV6nn(V5I#R?1hEUjw^ zXGij_qWOYTe9O#m6po`M-73Go4`aVxKW)M#4_=vU!c$-h0G~Iqs#_jDx%Eyduy?Wi zvD7HJG#kSib>iic?{y5y{%mN${b_Ur!UJOesntN35B6k$(MC%Y+($PSnP#a1cFe+$ z!koZHk@rfD60ZT3{1CZk3NIMrTgg0r93y!>@AB>>nEUH_81*}u11GXKW!Vv9t$yz? zDEbp(bRZLFIN+tnj~5goi2e;h+5xYk`;s&ZmCzTQlnZssiI#LwOJqjvi>Ct$ufOsi z%}f}EEmk+Ml3r~$w6+MAEwD`R97Aj^jc5`Fc8ndo%-|o65Ng}g%}6N*=1iIw6-DRkwMcP)BxlLA;cTZCgJ#>O{t#^z8iRS zf11`Gtl8^t?r^;l>J5+E5JP zi>AOF@RV6ze3?Z9_Ku)VlBhK>#I048g&5uw#LIhDt@l#spJtaxN!67VVAq6SbM-~k z-+Yn19f2h9C6xG~n3!il>{qrF z@++Y6uVZG+miABz-+}%cjNsEdu$|%9Ov^wmq|s? zQFEY9k5X#XV1lVOL{c*`{g`GT&?E4hNQ2x&21tI1$=uebOr53AUd!5LM75(@Ml2yb zg_L3)NfbY$(1zmK`r=dYb?;NAo*9~ZHBAeDEhH(-eLMJLN2}ogoeJgU`kth;#ETMWWLQ}XwfkH5Q6Z`1D3>#9< zzv4swv5Ky*+-g47!Wb#ZBSb;OBKsCzT6yAsa>8dtu%>Xxlv$dKYPS}^q?^_?Bm0;l z*pea|07rOp4Ry37@=}u+DO0Gk3s|fn!?zCfNZ1~w8eSL7X2ftn1r*3~N|`_<6mxtk z4wr!;AX}a=!aw6CQUkiGwk(uQ(t7fz(u-5*Y}6O&DRgM9et06fYL8YB@&|1dGoJ1; zJpb8e?ltCxC!%f(60RuOIuw!*K4~6nzsP#M(4A48VOCe?dntByhI}+i0QjaszY#iw z?M2E~c~3{}OFGY|H}P-oy`O%wz`4374lcpEh8QkV7jGeMm#K?l5M03IZzPGdms3Hv zK?H9(EBJCK7`T%J<#NOk{|$s`!^W{}%%GaE&%+W3Y)U9;1+&XvdRJ?s`4t#t5bh&V zPFtEwn|@@YG|?pbjBNID1}KJae!C>OY1F=1oSs9k{0<)w(f27l6OC$;ia6wgk@Zaa zJANR}kkeTsmV{Zx4&ip-5L-W?5_4{s!`MOWB^MJvKbatt#x9o)$^q&%OW9#x$W}#D?j$N7M__Nt5>ctzL`V?OL>qR1|SEIfg;lfYLS0bm$o3INn>pl!+6Dx{l$K|-V9%0sLPWw=bfo+uiYf;JirO1 zhpRc|>&fTZW5hUxIM*&Ym{Q5aVH|$hzxM}A;P%@jl$5kh7fifg5EZ^(lP)NKuZb3d z#%N`SL3N2`?4$^eE#<@Z=D~6=K>7$ahUc;aA@Y-#zjieGQ2=7X8L0gVOpzkYuhO5tB9^o6jo z->$A4^?MA9v2LlT(i`uLSS9zd;?7qFr6uUmp9Ptt7=pJB5PPI`FP!*Ry=qaarZyQ4 z&sA$5xy%g1i~(xytp>&yX0zpxYRldON-WQ8p-N1uEFfCtl1vsP1nHpyT@v2gx25%Q zsWHmD^HA=0Q&N+3lSLA5cFU4rY_a>vt5>!7d(%nGrKbwTVQA0sLN$HQTBKKfxVPK4&>z}Bn_6uvJ-TE6A@?lzHA&`tE1OE5VS(Yh2_JkHc4ROQvJ_NMc4s z8I+juv{2w?$a}l*6#9UCcY;G)B^6z znlmodrI$PN_%>T__`xw%PWo>@RI&IaiQ`N)0o{vD4|z2TFDQLwXr&=PtK1zF*`b7qYE{H@K#mv*p7n@Ih#>y%PK40 z>9M3ZYr|%o4f_~jnhw_OI@}PE>;3(^lP=;;cG!JGLhoINaxba~d_Fy*y`WDYu)c(< z0Qbf)^zX1VlHTeG_Zk5?O2Kc~HocREkluPidGEGpk!R#3fWWsv3JD*5WGH*+&j1EW z2NF!tP*+~h3~fiqizU7UlP;d*ueNkFuV79oamt+nGc(=|BC}&SD_);7O8jUF&CDWG zm$v9bbVD97PvHQEZ^i9~5biU8r6ijn0MC0K?TBj{B?r-fD~D>DpBcF40~NMxgpf8s zkt;cdF0QQc3PX!|-RCuuyWuZt1>fV4R6)SzETStV^7OPMyj zdD-f_GTt+pgfgBhlFuhF4{Pz;Oo_1m;!-A25EaywlCR+MwZ+PdaciZ?ds6WrP&NS) zos4ZfrSkZad={vxOL@YhIFD8{l&`2g!)HkqO-{!{X_=>1h?1(9ta!@w^J_!Ttq`RC zU;m`r{wxa=i?KE67Tr`)HCUEj3uhztl$F+cf|M1*)6FojW>)bOgx#4;#(kGFeg74p<>Sw-v(T>>T1W-(EorR}* zQrJOXbuI5o~zzRcadL_ zt`7C&P?7iSnQT^~ie7l5?5>;G-A70|_@4feHezn0FOJoc4eCrddlr%rS0Wh05YMAC z+jd}rjS%IML#=c4OAVMe0_ZC-#CJTH5ViZf;KIP&T1z9%7*rX*&xP$3vhOkKROIH) z<#L+TXq53iQbPKMqY1z|Bpi zu83K@Gdv+9uSG`FH=&YMR~jiUqo_O%!?$F*XpEI zCx&j37~KTy^g*r8X`U=a z>ss>lv0{$;M0L0oI3~Ad{0u7)c51TR@YHvY!n<|iFbDb#D~|fKDzOI8tNmz#gB&HX zQe1k(DzVBSvAWSodfmJz=yztkbh(42uX{BX!$w=`4JgLW{kuseX)LZZzL$|#{!|)F z?Z-o}NtO640@O?tW%M+M7e6&-TZM_$qzWqE&l{3DST`GmSEi1kEB7?BN1kwBey!wG zB4Np*iH6$=%WBS+HlJ2#yAC~88iR%X&Bl?bXO(T&NXNY#bYoy|C2q@D zLk^8Hv1E@cT9*0J8bmA0;wA!%Czi8EN?0!WeIcBk6Yvu$l&tSnLk?sSfucvncK|KH zxQ5v}#BhRtLtWjXa-@Ed%7o}dE$J2L!@j8DOu&24v+;Cg30*dlzCA^awt;E+QPQUvGJ#!(LK zXepSq5zi`tMcCfc8CS|59Z|+gjKxsv^(Klw`3KqLkzuEBA8qoJU8fQ?yF!c! z?TqH9_fP-7JJr)Ykp0&tedOgbpnk7)Y;#d5|j+0P4wKOC?TeK$*{4sR}Yoh(# zOnVde0wN#4nuWYT_rl!KVKtITz)8sZvA>qp;>ygT-wE)8EA)vaJA5T(5A8Ztd;HGQ z-obv#x9(Mt<vk^&xP>mY;9$ zn4Dv_hJlTVYA3bg%*eMvlYHa9k-M{LHh)W+tU6p=&5{G#UnSH;P(~SY{sl z5}{8dU1I3yQh?xEmvw3%5v_u|q9$qiHp(N52~{oYT(SRXY4&F}=tNIblun7N&xSf= zIwaClwsn0H13v%rW+44HzGXLB)pX~Bo_z}am!AC}jNI=9ZJ;ube#mvdk&@EJOZfE* z9F&MAoF-I8C^R8bsEA~4AYJZuEF5F(SYH}+#Bb+r@69PS5H6@8ycCsDwMMPpszJ^A z%n0-B7ih%_#Pgo{ykRpOn5OamZn5F{Bjv{=-*e0P#{F7K3_rrB*~oJZxA10P224PU zQRuX~Pjq{m7cNwq*0HQPk|E`KFI?!8V-{H@Cdb7jZp*N2@sed&MnB!!wKhhQ*D6}m ze)uXa7Ns3WzpGO}zK$~mN5?3NYlNpv4UM|j;s;Sfy$?VCvFEMx2qwKYnS`jJKYj=s0vsbOcAF`C2gg>6uwL)`-UlhG5aR;{W6ivhc$Xu-#f)NL+lUIxADKKcHLwIed=7nwGj@EmPM;kF*%VIauZMitvt?(j-x;K$Tw3}kSB z2>2QI-A!^g9P{Cd+Apprapp^v3TqoHROHxje~FBxR<+*#%qQlLMb3XUrR0C_R#&ufzcM#rfSVC)YIIx*^pKQIR}2tP7MGGu#k=|m5ugbc?$Iwj(brx+=J z%SJRGB9Y-DCzyygrsI-}K8Pog)ifG`E~edc9F@_u8-anPPeg?k9HQzY=9>2(-DOq& zCi*jOR@S{9Tzv>zrr%Y@J@P}NQUBE*Pf07zG#y^P()iG5KOUHY#rW%gI9jiOYIY_A z=5DVKSNws_DEc7s(VkGp+~uBIM`l-wC@ESkzdZX;zliVA5n;^4GoKEj750id2sd)O8iE<^|9@XPT?9G*F7FmXA1bB=@4%On10{EcZ zLIHid_zb#b>Q&%@%3vfHJjN;GPKdE^)1TlnCYGuf1MknEMCB>re5^LDo7&oh%BIzb zEyjzA-DE<^@W*2XlTDId7L00p5nVo~@s7rukN%KxuLQ3e{vcMo@$T*&;P%6?wC;Is z(}_F}gQ6cyjbWdnUp__SO358tpPpk6J-JOuuYavM9mt{IR$Fu^w|+e0me!lBt~|)L zAI5E7k9xc!Z<$Tx$hb=8eWZJ|h22PKs-;~w8(!UWeQ<(Ing55Oz0sUA@2z8a5uY>d z(SM+{P1B3b(S-Yv^E%eGK>@&E_<0X3d5w;Mb?+N2Ss7H#4N(WLO*hPAC{;o6X+5L* z-v&lN{x8ek$6f7IvOs-xj@MXXOvV*7EbOiiEaV7<>?4UXzv-62qcLp6?rbq{*UDvN zP_IelN4Wn#N{uL|?t<~LjY|K+tkL1oNw$XXNz+OSuFM0ekwx-$$}uZa9*+JFoX_r8`L8yOrNcs5bY?I?Tg7_nvvLy?JMW%S?hD zuD8{Af+0lr5&0{$cjMuhUBG=n{+d*vahKvsIeWvLclyBHDCZhYKmT(Ul^4)0+&Ml3 zSPlokxY2i#t)Xj4Q4T9Vg5^~v2F*eNrby(}A#hF1vPl``S2Cu11u-(8P8A+Wzl^Y} zcIwOvsKZxJG1yU%fM8_Urc{E8aRLn%!M}7U$d+^9-31{#X$9c2KL|nfV%lEWU8=c= zynvE)_7QDLbqY^@Awz&Khyoaoy>X@+@LuJ&&sy3@ymBdO3~ca^3r$byBuTB|9%xE2 z>9Lczmx?(a`X)J^9t_w#)jl$Q4qAJT<4Zh^RwYKHoL%wKEF z?q|D})+ut8I@oXxjjYE#R`85%?gLC8RmPr?euRKhOQrF(S*yEt+Zpolp}n;|s3MA_ za{-(cTDq>Evrbx3q9-9rF<2S6v2?@e3;N z9YWuvgJWA)u)f48$`*e(TwCX4bAZ^%WH_)s^{`~bO&F&klyg%kvIXLUD+#f}F{UlHZsl)#)*by_+BtXudTL%q2m8|Qd+JgX5fJ(^yz% ziv6#fcUB)1%Odb}U0mPT?Q1wxg9;m4OMk)KY>e{@5hNPerkW?Kz z6#{!ho&m110bnaRS!P=+p5sS9O1k%w%D#BC; z`MH}ay)t`w*eG>6`C~MiXmGZnkEjFTmU`Zl+UF?CxOe@O$>%>^1rel!Q~Qv~ZOeIp zPid3&JIrONGc@?))be(PG;0T(kXGBEG6uT>0VQhQsOFk!TnoeSaBqLcz^~3W;T@L#8!F;ei$b ztFdA1FX8!eiVAWO%D^l8OTZG=Q3EAX7HvRvpgz+I`hd!t!2b(e?f%>C>H&ln#v_MK zBobhufNcV?dZJ|0Kc&~OiQvl0@!Vsm&O~>A@D#1497WuCBoR7C(OxtC>EKzo5Hb3v zd96RbZP)@@IOv{zHrKe$PxkoS*4}>oFLhB4d{0B#n4P}`o}oE&Cm^X-l2J6wT7%|E zru~Apxc6jH3%|jhu5b6-T7sEIRyRC~t_3WzA`B!`@iX;{e@HZm#ut{lek_du>P4(-h3YpexQL~qA;ScW|X zj{pZLZZanf_Zj)xaopuY!WMrSX-0sx;ptzBCifd6Mejd~_QN4fPs#H`q8aM;!BZQf zYPEee+$GxY9io+*{4D!iy%5wIS|!UsS@bJepgJfQJgg$@Uy0TYt+Mc+L@SV$JFY7w zMWsLbN22XM8VewWvrIB`OkucaXJ~u>o%OBm1QjHaXjuU*yfVMs1YzRk8fRRwkI^4* zqFM*r(0*u#sj3BPzRzBf%Pw^iA;CRrrRqa_+aN%s^9T{;tM2*RcI+d3Lmc7D3`V*&s3{cEDtC+lxJ9_+UW-tJa1QQFV#_CC2$+1 zXXA;-aO{nu)%6YSyA3@qgAR@=iXd;-nrL}p^~MN?pdyl4^C$)=cgwqv|jo$t{a!RfW#TQ>X^$Bo}6W z4)1Y^(C^s#+991eakI4t5&rk-LhQMsxfNSZN8Sayg`lvoN2zMF}+}a#VVU~eIVk(2;~>>H6j_Z2mkD> z8>xs=i(y^e6ILjXaC!M9*r3qus&9CfT#hG`yu?Z(p^lBwL`Lh#to+f+PnP?`p=oL3 ze{`NnPe_?k4Om6DdsT5WXBNg4F#SxPyoex7>XqQo$D(Ltol`-T zO6nQMING}9m31}Jy7s?t-NZQ3kI8X2Rd{5b>p&ev9pi~D=y`1n_C+>r5LFHR9DPb7 zRUYzvHqIHXSpdT((>$g2dfwmqdEEy-?RC)KntA%{Ls#_IHg)fuFY6Wh;Y-K-w_w`q zRo|*be{&`o<=Hrt97cuJt*RmZ;$znfPFX!Bx~(qzR->xooNmRSY?K4~rmEZcl;<&~ z7PHfjHn4mQ%`~d^{CGvG@6(r3@^EF$G^)~Tb6d~-oe20)Xo{2R9}3N<=h{<_FNTpa zs=RI%k)+Jsf!s7mMd(OY`a1xH0rC)+$O`$l+E+VO{SYbTt&hg3D*(RFJA zy_Ig%&ue=Yo1GZiA7O;+GdUIJ|;gpnQL!3;exs<-pcY@>Qv zoZxyzp)ozd`ti>SS@|&# zIo7BeqlAj@2#p;G<_9!42^*NgWsE~@;n;%X_P=?&Nwc()#GM@tx~BU;n%t&W++ zSi&_$ArBZPM%{f*1_MHR=x`1Ky5N|~;oOe0^+G|nE)T%5p;BfdHSw}UlXS_?#3)oKsO+?st1=U|{< zda7e~s$EPX{L9Z%pmeM8W!r9WWdP5(vTR^^fLGBNmuthEFFFGPcJa`xJT1%{a)j${96NtZt)iMfLlY z!CDp9EU?QlmEKhcGT6DGRBVf=Spc{vk^9-(+m&^NfvFyD>mk8*!|c~^S68-(7b?Ff zwpkWf>ftr7njJ}6!n1i7J~*6M@8ku$DOHf%+>A0zmJ_^V9rYwLqz0135tSC~&q|@s z(=P^ph9oZczdKl8ian8-)yHYly0Blw-dmH=*ws5O%ou*PA+e~>7$|E*W(Ioj;&KKu zC_QO46r%+3P6?BWONzXfjc~MWjd8`D8E{tr(`R76KmIMt?8vNgM*IuW=qWDuY&tTH zaSm1nIKr@Rc6etwH`(b4rDnSJs0xV_#{T%kMMT=nhuxLU3bb>G(VBJs=eD?BNUk95b*Sgf# zQlc2?BC@YwsaG;B257yQ`!ErITBDZ86D}%-5u{?DAWUT{8~dB-b7V<(!hU-qVu$z# z^m`eU8-%Vx@-~oa6>)rNqKw3~QGqY68(6n*=kn_DsXMMtyo>!y^~OXmCy%YsBvzO*q>de}>K*|!Mu&^Q1jHd8P#JMUm7YkO~uPiV8y;OP)(=INJe4(tt} zW3-v;gjG|OJG;B`*f3O0)cJ_o9AYAq{;)LfVt}Tx=J`_71Tse8lH~9EuxKw=P=j%WQ&m-Ae!*AXb-Wt5Z#flQtrR2DH&GOB0FZS7dqx)kR&$}Ag@ zL!etnRm(i?RYS9R4YdbmZ~Z}C@STzC?=`OxB@_qrAwYsfZj1+y(8AxkVMvBar!S2K(;qjY-`eR;#)ywmye13~RC^bfloE@vl} zRX&%x@e|)#!sAajs0Z{g%t8UScpQ>c*5n=I^jaS0gmvqQL}68rMKRjf?+nl3!aRi< zy#0`EQRO#2kMFSd1}t{|q4?cWgpC^wE5itR)f5|0wNb)-Wn>|z87?DGT-{UtYChm$ zCoBw6bk6E@!-8Yl_09W%W1eHid_TMTw~YoTmPrdi44%v^opw@P><_?;D#Jok3~>?> zhHMrYlL;84{SW3EUenlmPyFpUCl`if^SSZF_T`njR>*3Il6922-VZhiMAQVhx9T!v;N;+Cjh=6=jPSIQZq^cS+E(244!^aJ*yt%E>TAk4 zOmy$Zi^x)zm5 z_@^RjpupH&eqglHNITLZ;k7K2CA0YAgli@^?`CU31F+jMvx~z0QTD4mPkrhA?%AK) zSVi`kq!Vyq1d`g7`oRpqax>qlJ-Pn%@uGe6latc$GK_TkZJ|nEupeRNvfZ&|CiQoy;(O zU_>=E51UZ7Raghkw@9G>8$VtNUwhV+r*0b8ZtD3>_4}q0CN8k!XOA$PsmCU8NAvZ( zjKXnQuF?VFgN{sGRu;4VA|3y`j@p_0+EsR>ZY=KUS*~BMmz`jVKe(Hb$*vy3AtxQb zr;prTs65!-eRlo%&StxKP2+BhcF`=2BIQ0>dc;qZLo_u*jrZwOLF=NiUc2+q&p^;s z>;yml7t1EJyBPq_@P&xv3`feCc;kDZ#g3&$Tcg=!d~pLTPV)T6heaB})Yf+0U-TOH z7COC=u!@0ddxjccY0TA!m8)q!8iC!t>3BpdBu9E_;?USHu5Yz?E&lQPU~xfC!w_e& z@E?rkt6?M`Cl4h5s#*WdR_$v&a6DMVZ=c$|TkUmXw%bE$4voGml$_vL28e(=Hk6tb*KW;f~6%oS*)nXMk-G z#v2vr(rjrQDOx692Y@E>>zepZ+afhFt{!iG57)-uIK+4Vj#{quTwV3{qg6XpX6LUx zSvrOX2QpRLle3qsPczwSyN^b)Xn7m!Jx$J0BM1LZSode{8$93jpP(ieKf76OdKU)t zhdgF}I8q zNyaX2{2&$#@hX^+CES?df+__LCC-uPW}E5Bfv#J*)6JpL3x0D;%|=%d6y?#}??-ss zeYEYWFPu)nwx5PURH?3VoC#S7eWX8>g13@?o+yGkFXvMf8Y|Dw3CQo@Def&A>dX_= ze=(0sa?Ft=nOUYE94!(%k7CT#jdLX??4gc&EasjV#EjLJ8I$feA|n$oSJ)0ThI2c* z0SE_EZDf{WO=)~8b8UgGP-W0D5@a(7l zLtzGS&|#y&|A4gM@ZFS4Yz`p8QK>ItffV=l#|h2?eda1-PE3>8VgzM1?MdTu!~@K$ z%j9yiFzQ)9)FB;zSd{>pxs`B>J!vV4E(^*};WbNacpIBx2Gg^xHktKI;RkQ-pPLlY zRrlmNX<4GWOVj(~Q2g5Tw>~R5Od}*!i>G#lt<<;~$sW4`+IV%3;hMnY`Ddg}+?2&R zS__+9QMeD0wpDf6_OD2D*|_Hn{Fd|RoOg{JM#9`Av~>L*g@!Jk%j+S#~F)G{9Wg6=%{I@)6S8?J)0vaUtC zcHD&qe~UP}b}2iOU~;t1MVyf$Z#1+~3<5ZSImuf-z{TeHzo>c(s5pYLG?{1pYmZ4hJ%DA*2J{9T}_&)RHqbM?^XR|jj5Txypb zyp4^J@Q?C$yeqOtpA}Qfawc9*CbAJ;T~?B0$Xar-ovjt;9SMoCb8EvX-U_kz&J^IX zP0*7LVPEgi2K-oDtt+ zVZik?rBi?IKACkW%x})5{hPNZ9%T&Uj3%<(l-jfq8FPwa`GN6gVT0Mp{cr6R^1e~y zDa+k&m}w?4HqergO!`#SVL$A%HQOe`1JsM@hT;j}Gq zs5W1EhowJaYsTb{P8q5!^*dT#_g(d3sN&b3iHb>Y%)4d*-Wr0c3r7rPW^P`TXbc7@ z>gxi0sP@4{j#w3;`sDDdft8L-27sn@{-1sB#le3zc%e>&O18+|M6o7H5|F-9hrv5S zRA?s8DzxMXj^taXiFRRjcd{?y&B`+ewh$HCkpdv+&*zdV@LCb;=Lps}-{1z1kLIr0 zWc`vCe{IBq$eaB>1?4_{bt9PC9ERKMU@>fkL-v#r$KPn^Wjc|2^WchOq^QF3NEwW@ zuY;GOs|Ts~mAoAA5U1kJjF4I?`q|&42KhjseFd^A`bCC54u%odrPyA6-KVe1tn3Kx z^GAI3#FG>6S?{S4TrpNY^G*xn-L5M(C!VK|pGD;pj$E+V;TPuuPshNXMAPUI+pfipOUHYG&dH=AV;Z4%Y^OeFGo z13hyEXIpNSm03I^r@;DknL+H{NOUiPrdPI5ag3(fVTh#WP4@k#-0+V-wdYBF$hgVV zKurT03YAyg3G}`}V`$wNhBXbPScK)bUbbjy9p>5hYRX;o%&TZj`8Cc>bng($F&S%; z;9*WU)*l%zf+lj&MZ%0vfN4uX>?y_kK#ZN-&jLv`FgO(w&`SNpI$^Xh>|{#fL_Y@o z9WgG$n4I1$MTVr4@bCYOJZz#SnQ0$udF_^fA*s|x(iI>`(fKCt_y3hGX z1m?aRH8dnGu?}45UM#s&$vXT-3mbxZo;Qsa`|`Ap$nggUW3-P;{o3IJ7gUH65g<9N z4>XsLfDbOI%y=_#A^o;F7S3LnCFQAI=OskxzxdOC6^AViIDOxyoLP5eb!i=@A7$W7 zoAt^zP$sQkU|fY${60DRy`R2f9s%h4&WSBkBe@I7B2G>a6znwo)JxX{!Z%z}uom ze7gtWGFoH!jg)~C+m0nCeH47^9ZcUKl@~pP&`gCn7@R_vlj&LW^~uj^y9)*sL!OUD z!$TrI!7B>dUIVRO1j&G7^&QeSoV)6ya|Hr513|R`E_q*Dy#C( z%X}FA;fd?InE4Uvo|`3EH#%KE!+CQ5fI0j&U!X{EuqlR`?z|dhVS)2#}>KBt}!g zL>K54*PHCmVR%C|cmY|u`lGzej>!VW!tN89c`~6wtjmeZS!Ir>K7rG@qVJd+Iq%fc zJR9p0^x@W`QkG}+TP*g(k-`p&_XrQkGpp3M8B!pwW`DF`_u~Ne2g%*)pvT6^)w$qg zB1vvQMVRdGH#3eLEx|PGAgnIY6g!6RL))^(Kg8~_9_ORGohd#gY=O40pTuf2-A}iU zsE1M<y2EkVlXkyZ;b%rG>oY;IsBHen zd7igiLHS3b%G}3`> zXL17*r6^O5ez(K*oq<-@{@UDG@UNfi^i`o8&7rh@l!}*TXJ2gc;!RFwcY$P8L0Yz< z@{UwXpZ$MFWN>pR6*9cVG<}llAEr?y3jvj!P=km4I6I?{(V2Go)b8OP6X6A6d#Rg` z;~_e<4TuiSm+YxX7W5)S%Xtx^Sv?EUj`9 zetX(Q>u-%SkAJ1Vr*GXz`Ro;_(9!lI9iqSZdxh zSx2(EN=46<;C8wG%+5wlh{BXup4XeFktD&A!OEulmh*-Ri1`mWUpo)|LV_YMPOPQg zE6rMmWk*1C$iF$As?vt9sx>9#>`hYt22??>IL54-p`%}-^kE2*oNy=>j%#mp8%G|~ zrY>YY&>koKdYxq)RIon=g>Yv0yHMwNgrq3qD8UWUU-*0q`T`cem#!~%Hc$e)9?g2D zD5X=mJD}Jlx74obN8D5PEq@`@-a`8$45d>}VB?0&aYL5DXlr%nUpG9&mt(ZdI#LxaAOF#aW1yzY@$sxAM2bZBs| zI<&z5t3xAfCrF3r(CB|S6yU!L{69K0!75Pj_=^xt=xg53v=QtWg{IHIe@A$4MS09@+y!YsAxxe2! zWu9KB8SN7N|LD*tEDjP+PL$}60;SW1`0vOgyPK3^axUF_MH+M7Iiu`P8J<`+N!{fl zt*biwTwJ8)io_lV(ZK|)tRg5ouOb;P%KL$mI*--&ZXZ+cNGJSq=7vdRKw(QGD5y%_(7<3)#tExTi>dhlNz+Pmo9D6~EhM2J>T+jwI}V^rLgGqcKMc8>IY8gWR& zwYOaLTC%qe&3GnsLY4heD8%4hk?SMB+5njQn;glm6HO*1DxS0@WF8@+}0x_Uj>$bTA(;ZY*6(i^9LHjPBGG*Z-wo?8ou|cN7ta? zoD1in1tmY4ffFylA6<=l1PMnjgrYA$u#;umNAoG9jEvbCqJ4flIuTO_~Eq=7+op* ztWUV!$v87sn@;XG8A@QNWrI% z_^j}0F2TCj+H-|u^X({M7V=*sK0}QNYs?fl3QCJeT{FU*U|bG;VtM0#V>JrjFH>HP7LuU z^##lRNXRjBf+RZ_2o*%*z;BR8bHrzMl>fFSJZPtrmIySZ2#YV&wH?Unv|?$w=h^<1 z(EKn+86_nyc~w{>l-+QUTNt7jFZWSNQ>kTW662@yFC>zCUAziQ#$$=Z_ohcm^as5{ zb$Y2plI2+EEkEaq9-4o~m^>*FcNYO$UCF_?616p0a3H6>kA`~vML`98g;-&nqx)`q z?2V!O1-pCw>r3vztioRwW5PFvm52w53f!zXz%el!>sg*K;^fUZML+!<>0;&$C!B^z ziFx56^T`nx0CJyuy?tEa%GKzrDfH-J7pRgn{jZgV| zuK)*;c7&-@WonR}39D4UkdXNI*iUTV*xz$UnisyEWjA0hc@d(;>*NXF$)vJrMQWN+ z+S21Hntaph)8CZyF4qzF<2X8WQ+6_G|08Sf&Wj4WrO*H~VdE_S9S!${Qk3!6(4_PK({FMgiP zi#BKx%}i^2(%qxyC`)c9+EiB?ON>F={iaFvpZlTNvWVjAwj-rXrVuInm zvI>()W0m32StY148DV1VbB{=gm0Hg2^MZmuEg4r*<~PJ`kA~1lAd_JfkY$q3?c+?Y zv+LXDa!NvZcmAfoKcf7Hp2g^Vr+BgT)6RYKX1%?Ne_FQ+x3bt${BaZAKhQrYNj`=9 z%|s;mc)nrgUsh`^41eP04oqG`CU>!d4Boma9gG35hym2MWDC{`72(yc^md{bazmgP zHUBLjY6S(`2-0VW@?GPHTtX98WGg%P9|K$Dc|mh7mQ723juv+Y)2-xbvy#DZ5wzPm zfRzM)pp~9cgu>sV6i-`_4p0txJ9prQ0#T%;TjT(CY z0xYnzRV^#Yc+r5W?Loh}fnFWf4#>UdV?yCJw-xle#L%MRa08Gi@ZD`-ZH6Q<9Vgp*AtjK%$@%3z$?~ z{4`2hBX*rZQSC_5!4&&f{O(cJkcRxsbW~9b2I%vZX+2Z#RRZKiWdQTI6sV3nL*_ki zVv!Xv)-tGX&qxta7YSn)Z5fs*BcUe&-x$uG$w29tw)@#;0JmA+Hsr4Vt*3!)Sjm9Z ziM*4*y;3IB6ZWUxunlJCwNC{!KYGNRSozN!Hjtf2=fclxwG2KZ4TLo79K5e?hUblp zI^}jk$Yx?4DDOA-ENBKCc%QR@Kg>8J92t| zDno_gpb)*S_!@qQQ9kq5kYfj{3}4GNfuS)95Oqb~jB&($rCFxgN(S<~yN;q=Ub$BN z>xSB|MaUv{g8U}X(Slek87Yq(l_HYpa%1qw@sg&8A-s=YKJ&0wSH5tgKeqzu0Rd`W z!bG)9UCkRmID^D%Dj~2^*_9}thM|jo#>PK4$CCuzs>Y?i#i^#2Qv;NL*X zWYv#B(L=q|)lw~iad<)XmM}*z<+AE^;lg2FZ0~Adv|yi6y)Y&&^h;B13k>2*Q&VRb z4DU-@eHN+FD|n=MKzwn3WNvYev%KYy|P*UYw( zp7<}OKZY8w0YpsNU%`U~6vAsS$GX>$82G^2*Z$TXZLfgd=ioIEp8xDCIR4E0nv5Y- z{}qHqExv%JZXTfOYqyr9KKPf|pse#(+oUvb;5C47@$f5vFSU9BO%uvM#n(+C(*XLv zjwM$c`0;fwer*UtdXCi;ZTA1UEn5P&UK3djv%C%>ZG7yt<$X>|yzaYtl}-ECZaq8JuYmQh;H!`A(SMH6S~9TVwMppm;XmLG5AJ15wZ%ZE z*FtEcEKoF1FNM$)XMi@Z=p#E6}@U* zz*FdOGT`@YP-smj+rVPri;svj6gTt>nmhvPzarK%;4R{7n+_D@U_v64#2P}q8V_M$ zGhY*Nm_sGM1{tx2a(}gEVZ!db4v5JK$_@V|$Ri7^@@o$jPT1~O)SLhXKzOlsWI#cv z@Vp5=IZzF+C|Vk};}t2&!~S`Vw^Rx>^@?gLpm=~Un*}=R%~%6dECXb~aZONo;Lpnd z{HAU#*oD_5S^BVZuLC6NfKq%7XwwZf4F8fY-VXNg)f(Ue+x;4PZwd-RqUXWX{)94r zMFhW~q+jE8f?y%^f3~izKye#sToWTFEMZw7Xx_lSO>sCDEjP+WD0;#^cm?}0WhIo zkfSXC2KJ>t`^pa`Fr?CiY!f*i9E45JepPM&2sxh-vKQbM@x`xW;=?qU{oy}(5)D}} znmmF5N-!@*eIHZ`@G%tZ>mZswv%nR+MjDF(WWBnqJasaI;}M=+_7RAh*m&TWfiEeH z1mHYglli3q{xg7{_i(QGFV^J-0EEuZLt$$HK&{EYN(0T2>DBhm*z|0{Z52nQkYbDJUn8bab{1crt7dW~XV z1qUJVbDI+qG=#*@=n5AaLgHtX)ddG3@iX%8gM*Ox87WgkLrDCL2aAo!~E!r9~^qVm)J8Mku1ZyJin88t#j8f%hM@(S~B2Sox3T3=iXHUnY8 zk5A$CwPjm%XC{6X`{Z>=VUtv4526u6vq4EGZ-1p9O342CjghdJuA=79f8{+CLgy>Q zn{Xj&x#mCq2Ig0<{3Px|fZ+OOT%JDp-aYjH>d!-9J2oG{?0NthhyY!b4T=r~;HM9S zqY}%bw>-7{O=~KXcrduEc<(@Z5A{gzWU3sA=Y)Em8q0gkaZFb2@P?B38s1j{znFiX z$#?+TN}YbBhAV>&|6XGxror4ZlZ8gt2rog6C7YSIa5>n+7*lG*aM*!Wn<;*%%wB`3 z{`_Wjjv&xy_HR;ER3v_kH`^&lYmr~Bv0~SZN?_e|v_?U5T+z$>^81IRD$Y^Fv0rw& z0_bU$#8G%|>Zhw{Bp@3u1^=I$AxVXsa`@t*>ovc&ljHci3?1m*o|><7pkf1zKa0SM zU)do;g|(gBqTW}xht>AIc{qZ-(7*I@?O~$0Pg(>g#2WItJ$F_K=w25v4s;` zoiLZcc`PcVKslLoOf2|GHH`>Z3Qf5vi8AezycM{oQ;3?xo*%{ww~=q2uFsZ-zIO07H%-IvrztkX+FivYzN1OrOrw>44N?IpVjGa#pYJ`3)`lJEI7P0qRKE zf-IqXcS38xJ&$0-;MNkMQaPwA8|1t;*&32Po)aAPH&S__Y=3!r?# zo?GUG&;fJVxxLutFzR>N7GsO=wyOV8oWvM%fg46}iFu&l^zpxX&|vPOA9vr3#uQ$_ zwyJ64#sr|820Ke9%l{zrTWxF0$Ubn7$2>!PfyTD|m%VkCG2gPR=N#o&cyt@_jUEtexPFogaK0B1=hVE{v|p9g zUgQ1MS>@iMTD!c%x_ms+A$lv!R+2LrLqAoPRJHa9HEB-^kW4-?lO_h_I=E~fhlc3} zzk|D_-&5w0KrtLioPP*MX8SZ+Q>* zUsl3De-G6^jPrx5egS16qzouWAOs&90g&jHzUy-}kt8`0RM^VS%*ks*maasdc8_DR z%R?|n*74bBF2x)AVcP_z_yFJoeMBB}S_=B|MU{YVllmR*(59!@AOl4vE@ZlH#TPEl zABa|B#DC0$7&aMtb~aM`lfGDqP9TlXYBV)^W<^ru zwS8O|Jh1MtZKg45lqtX^&eBI(;t5&O;)JYiNPVH;l%p(gnZAA-nz7kv2WrMlYR^r? zy%GxgA_rV9wJ|#Uxo5M`x~Yd#U~;SH^-T*h6|h~jDqYt>XMts^ec-!^g{_mnZLWAi zMKH8xAD%Mq@K4u++}QTu)Rnp?V;;my~zi}=D@BGSd8x{@o2BrPwiAo*o z6${C>)($(E8}9R0UbCFSqoB8*(ks9^nu(*7l9d=YwccT)#A8Gb?+jXTtf_qzgu5t_ zUp8Fr7$5Qam^F=DwG5Z}91xk&JV@_`H9H4!E;dCFBC>i1$L!+7EkeW?Qv2#Tgi1b= zO3KOH;3S>22LjvQ<8L!dS1T@d?m4L3H1P5tsgCYqSD%;VtzjBzID!b+Fzj(=Y;=5s zY!PGRV~qxxI1E&4!V9+I6lP%5D3=oeF?9eEjW+}7U3ZI;C{a5+QHz>(Rlc*62y1Pv z1Hq%LUY2av^1JzmY`0ZbGb*t(NW7zV3|46l>dVu!U7f0%3ye*>DVNK{g|jYi-O^ak z5wBPYiCo5tqG1*9R6t<{UdBzah^?wdRi?5&22Q#c%^TruOTQRMSuzg}Q(em{=vQnx z5Y^$2c3WZwj<+{xkAJ4j{pR|>Be8uGqa$Hha8yC?G?h-jcu~BM0;2M)o%&4oxcayb zk2=LG+1qgufH0H8`c^h9VkTTpf+~ni{5CEX{iuYCG3mfX=sl=?nzK8|Gxck*v}41e z(6qY+Tpu*q!P&zG?T5xq!OznAoodMqs?&ajq0`pQ2y+rbi@`!% zh3?;Ysxjo#=Z$%?C!xpn^p>U7u;lXZZiy5R$kfmpqU-w;PWkpfS$pI&O_HE_wnX%M z7QUPA7rjLF*7zp!PVB}f@IL;+9lhG4Iii!r6-eL{rYEMN;@~ZapTBzn(6By|zo@Tv z4EBrWzJo0|(9bkqH4gQQl|O)Et_8=N04R)L6wR`_`9n9kk7+XBV=|=A&{vtpHM2vt zL~uJ%aI{=%0C^<@5c>K(sP5_Bn&Ri>+%iF-Q+@$*(+v}7IEK4Z#D<}l*bSS~F8q6` zZT(u>`uPN3{FmwkMmGgKpWtydFr?u3d{7vm0ZEmyBIa-3rTQQI`W-bdG zDz*7EW(u>&YfAJpt@M>6h+>hl56ahlrWLw2*@%jWP^LYxy~k3h=;Ch!^irbp@N=#5 za;@5R9`kbj347Ps@+OyvOsWQ*N~DFcrN^lBMb||@d{36E#<&o8{47FIRuzR@E3$&*hpRZTpDx1xf53k zyOshAfr&KBvQ&<9(_)))Cp*rq!zOtEs5ZLz6DoEV!Pr0Mrq$8QKT&D2P^Obk%pT+p zDRQ_2gKB9e6uRlYzOw;aJ^2|Edb*49#U*rfvfnHCCASL=Q%C8ZEUFutTpT`KtsE{# z?YFLzrn{t+%nj1p;*o&Zf&hBOj7%rKKBKkmW&s(a%{$FtW?fe81TM|7tdaFc(3C0{ zuL`pQPD$3mUz#R5R`eRdH0N7ng*XI-Ivc0y>`yzKJbA1EI88R1Th(0W@RcRn&ZQr6 zdlbmdbV9mGQTw;t>KLgr?8L~`3`Z7eEKK)U2IBLXO)cB=Wqqa@KUFYHC_6Lr82?Be zX_r;8yR}It>`^d|oW!5V;1>W%fpV?-xwsO=camZW$qEQi%u#G2OriV~X+QLRG%Msg zw5S+w1pK_}#Sqz?0BQ=h7?oacZ<${ktL7y_km{H3X0_Ha20-C&e`&jlv% zT!qq(2GPB=KQZfLnj8~1G4BcL3Xaazu~J6p6>@tl8jRFatSQr^Hw}XRG!}DYH^^HQ z-SgL%MF*U#VBzW{Ce1^KE)e2ARrZ+e>LUq8@rYVYAMj zX-pjDCcvl9AMi|RVl;RoRA<~dob7V(!zuo1>AAG@pL$1t&q*@FO9|5aW)0g`-MH1| z5j-@$VkEML@W==+)a?$L6@L$cuRXQi{NA^fP#D-?yr&z^HUcyGL!^S%94{q~w+x^Y ziK-^T*_ohbq^gekEu>j@MP!gGQjdH9*<2Hrk~tWR5iomJuG+LqZ&f`yyB% z-&m4JAYad>5YWN9gaJy{R6@GkS3o>JZttRCtd0L9YRO=n{g17!=<&>qX z5zr$pVj$gwqO!d@P>{csX^uF`fOMI}CW7au)Vik)@HA@(*$L!*^v_h_&ah-k=pJWB z`dB#j4xn=hY$EMuYaZ5vdC=fbozVD4N&ZW0)Xg%{FMRBu4mEGCIBKr8egEgB;H0H5 zBxkY*i9vkiIbymZ(FL3#o6hibTe!Z=O&ed9LeHHAJHb@f@pbRipYU3U@V1o<653A6 zmo~wLf%K!lBcwr-A+*E;=uh-*lV3J}hf9xqTZ7RmfQvnib;KiU7~=o*@eP?V&L3(u z-;dr57(J-OJ%kmKRAb(-`}8F)4|Er*tiv0RpZ{edQN$eA1QO^wkmarkj$Ff+>ko zBQ!N{#+rNJWY9vlbN+i(_xzpDOODEu1va*NzU@kk!6bpKwFHF&B*cLa#00NfK`zlTcGZ9)<(F;>i1mV}nV`p7hw)!H#?*rc^u5`xGTx@1V;;9_p!5 z?}VlM6&=*$MAEe*Lx)!sDwOkQ_-(%?JiLrl3j$*Crih z+66;qV~xcP52#sPYcw%2$px{H3Qc-w#S||(ddwJc?Zv#KD4azor-ScXBP{>=Ny}e5 z$_wz2ADbGyMF)@Lj_LT6phg`lu2Y^GSm)_vrm!__8TQc6<9j{mbi?PnQX&lpZy*0J z(Gtij)4-GHaL*SPUA6#DSVSXT$tfK0l`TLWgv-`zWP5HbsOR@PAj_y>WSo`FeT<(n zOjxABw3_(Rt9CUE)m3hVm7jQR_c9M(*vk_Njvw{rgwp72!#t)>Y2Ds@{NxA|+WSA4Mo}DqWFk;cCMG zGCUfJU@iI3L=f3z6@%OO-8kM^qHLfJ7C-6j40dTv-h3l@N{q~RLXE=!xBb|%p^797 zJf~&V0&!?)ZYw7i*}yW9RPLV)tp_WED}%EgB;_{6X_glBGVs#VZ4s(X-(8XIkcHk3 z4mtASbA%M2sC^HoyAXNNK6=dhI_jel8*oNH-CGB))^58c?Dhrp31ks#^ zI2YtDEpd7rhQzaC7X!nkIQvL(rVyVdJHAAO>o1>P@1)&^0SDD4#s&>ah-pHtlQtm% zp~b$By)FAl-0GfXZGf;Ir=eO56l#zuJ4$TdmT?JBQe=ddVM-gNj~$^|Fe0ug0!Vy5 z7+P^it#uQ=o;Q6^Jcg8R8&N^0&`17gbMuOARZ0qoZ5nyl% zjI%%`*!m?4EIBC)obgobA^6GhRXIjrshWQ;Rnb_$aHE;(!8dCY1?aHO+&4-W)g*g^ zJC2Jbz_*f;f6V^bxE98(w+=H@1%%aTUe;#$yQIjr_Q6wungl>I)Ryp+>3UC$<3%e; zC?1b3SiR=wOCE;CFJkhW_m^S6N>YS!DF2~mpw3{Y{oD8E@IM+@iu*ZJ#6yL=rG@m^ zkdz!|RpyRxq{Fy_RCEb5S32{=kQODRaTdqN;|ghJ*tn%gPt|h%|0cU z@d8n=0^dU{My}vj8`kw-rF07OS7t{XuEna2RB2i5L9lY7eKQ}}7GYG~#&b2)XcvO! zH5Jj^Flqc0-;yDkw=un)xI_VIQZZyD8ZZu1H$1|%D>cnzYH{0?R>+Kf18SOpY7X~y zlNT(e4Xs2%EmL&We>_r~ZuLpFk-u28Nsgnp5C z_TGP9{IEeNX_ZK~c7qE9oh^NM>wjdwk)T5#&H9}hh8Badc8%f1Ht$#oLMS*Rf_wfe+OM@g!MK`2Jn^5B|d%igmINNP7z;^5+ zU#PMhv0zXBxf4X&t>oXm<&!;l>q6Coz)l!#FBFkYd8e!}_EGRAh_-sb&L~#Um*(gU z)^|dCo%BP{oi7RL$+zox-c7nrsID`X>%=f!47N|^?a7*_hI@p^Fhf%J?^X0gX011X?zSHB*5H&fp)>bG+c3G zE2yxMUNpXDxQBZePD?e_Pqv13R&eT?@tLnc!frbITtxVf(4RT~$J=$R&(x%_7`I&<_vXAinM^A-N=YBL9)@- z8MUX(k=fA(VU5llJ7kA=kT1dP-VX`8@6uIVt{8FLlU4^|5EBK zJj60C-1NS>zGxmfD7K|K=XS2XCTs%wu3U=()06)s5bNbF}}>$pqS1jH?ag z?`()4>SM0%v>8Z|^&*p2(yzySX=|n{fa^d`1a%^DTCnfKrYFYt3W-0(uVyany80*T zv22RagT757$e`~-hb}#(v4~ge=jXc=6joq2hRF5Zm-tA`W(p{0nTIxP>n|0fR@quy zm2sB_$n5ZK@(fLXQL|=f?Lp5avCAeHT*Q|Ig<2vXBJauni^wAUb*K(I4p}(K_L5^! zB7^*}kM-X06Nkc6Ir^?o;ax&o@P+dEv?7w+Fo=H|JK>AjpDl{tPzZZaaJ|>mSazebK)ZTct5zg9++;Cw3AJ> zD9Mm?ip#iNUrk94Ip)TEJYY%l;HGbt71J9EZwUB$Q76hXiTo?y`CECjlvy7N8*T_0 zm9(&VYzx#bVvFxO>xMVlu_)ERCT6y3|9*6x{Tg6|-HNlABb?lvJ-U$X1m%B!@84bw z8G}&?Uw-f7#}LTCBF8{P&>mK)B!(n5PF_f_4h!O3u8x=`bDT`jRLGXQKvG^-8Yfrf zM(;J9!EPkkniwyS(>j`?@y6&-?@%vj?MJ_-MQV~Xd!8zu%Q63_&f}%?)~oSq?P{pP zI8@4TqjyR`C&Et^MQq{qyGzzYq`<;Ix_M$LmP%N<=J9)VMS@bXEtEvWt;MM$oauUCSM})<*UEHV<1+fGYDX(-%?|mVE>?NAQg|u;mqgGz+Mgfz(`58S1onMxBA!J2uzIF*41*m#W0w(ZlzZo zOPTKQK#Y^sn&HzPj4Fc1UWAt3`}2<8FGSO~_s;$uay-Xhwi_vp z*xhtlit0}VxkI=!`F&Wcju5QObxiICrhz50SZisrjgskK$Ae$ack zCk((7Lc#qfgUzmwp-+)__q;+|U5j2Qy+NqnO|cvJ=ECA&C-r>aOaqouq9KMw(l*+v zshnV!^yKG?l$rKx z$V3X`eZTD2DwoKN>jUbUq4}*_DsAli{JiUaTk91i8Q5F;MDbWf?N@PRyH=ps)*_29 zI}6&(JHzpplI{PJ7ce@x{=401hcb$D?+!+2vOF6m#L01Vbc-rI{0V&m8DCHal;5=1g<+C*sI=FkQ5NB;+*!GlGcLM(ck3G)Wz#u@P=lOL}Qi&gbo+1F3d?dzD|P*?43bot%8ayeH1Onu9$OE4|wP)L}a z)`h&jq%nx7!r?4;(c&QIAbGoTJRNO_S~)*3_vOgeKd_6Q8fzlu&^eT%G&xx|-uhJO zQ+k(ASPeo#>?gjTt&b=U65#KvE-Mv-AK(1Zw zs8L}YWIx3t7>Df@7ENc++PIivmHc-cxad69!y~LmX$-U6IHuvoOyy%j{)9w|6=5!C z@l=DV_ti1l+(v$c``<^*6rNLwc?~=+1+UY81R)CD4}q~#6(7JROghCO6m_*GY~cOi z_g1&T9M+_h4P!&DS4WIsLWQx8Bq#pnBN0hP7n%xJ(~X#|o-eedBQ3FWcLG zHZ~SFj~8qjjs0VIR*KtaHkUR+WdeWLAl(~oSdP2pG+B<(gRp&ebqm66a&-}X zJWk0r|8Sf}_{W^?R9ZvJ{-w<0SyBhFs&?f0K#H6##_qE#*q6mSZz!)%0iF#UUT{b2{%p%7$)rEf0AoWT+Kz|NCSm zISn<9|7_cDPGt2DG?_)6X-U=*4*t>MTlRK^5gsJ#aq+9#9g+69RVVeV<{}m*yT7V` zSR0+sDDEukcKImkTUblbs*=E6`_sSE>V0!!%@=MOM!<#TNLTBBpLXx-o{q0A1r9;^ z%l!?~kBZKn=3D2al!#Lu8Z5Q+7j-zo_J6rG%pBl+Ip}i zA1-ozIfW(Az;F{RXjOzH3qDUZwOO6Dn&PHpdD3I1a16{(7>Yi@V)c^O9A(}KW#SEB z>((71Ww(U%b9_mQchoe-9(wDZG4>$L-8`r8DeMXtaO#nwx>4`VKmOZx0|^x>VX0X8 zlI%F<@YNCq3~#kZ@3OkPzokbyh+UU3>#B&d+7gvteG>lmHLO6PxZ(aOgo% z4AR%+;FovvaTo<4nB)Tz`^|utchQztu0UP8%i|`;EJ_+KoZUqpBd_Z5n zEpR8i4=0r=ACZ`1hrzLsPcGobBmf{CWs0pskIPV_!>szTlus+be1i`dgExj_iBXAI zfo_M`5QPeaOru83B-dh^WN5|Kp_*fyWKq({mF~yh#i3)UQL51X7{sR=5WRs7d>f&T z^P71C(H0{efDo@iPU8x^l>q4ld|}7_&3KE$E~yoeS%Wo6#}3 zSuen*{~MwKU6uA4tWyDiHzEV4S#qhY+it@hc!ciZy=L6BJ-pH*tqua)LXl_$MRUWJ zOuE|U_c<}L3|jnspXps2!flx(9;hUqz$zA56{h4fDUC*{I6*GX)|>mQCV55TT?cfc z$orK2xXsfVPuMddv_($>Tcc=z!~1x*q~C*Yaw0@Kkr!_)4%U2X6Uhdw+VM)x$M}Li z4AEV)WR4tfRG@Djs9=G9ASe#DqGmfd~LOa;}7K#_F;fkxXwf5u<_rgU8pAL zFiX6ly?PC4AHE+W=?hPQ|Gk`GkZa3*nFRKH{lG#7hRguNBbNEbos1ZuvhW57z#bd2 zO#n8UdGsBL0o?`(?!aZikmt9dQ;}8ZD<}mR%f>Rz#JxVfULSgK);%Kfq>;603j5{2 z_*Dp7LFnG%&8+um;=4$BAH?*Sk%OHOgDA|Xm*Uu&*J;I1((V7+vjwpcW>}n*ROSy( zCe13^xh@aexGRl=;Uml{1NG9i>!xV_hippA! z!dk|Qos;FrG?+7}16P5VuTrrl~|>x zL!vr1>yw|7_fOVlnbnfOa7ll0>d&H+^0JC~!#YlA=<;TA{6P2@)h`&{;yh7(RTg}l z_NJK>ddDK>3Ln*^P}PwmHV+gBxh>3=dT0`k>ruvVZyWLqGpy4<1JbTB(2bf()n6?{ zx%Ct2|GmL1mwu~Wr@?s1y3;TEor_!B?UE*;rknj=mn&y!1e1zfSxd#2?PDuo;Ny(6 zc!$$4cz4gN+|WfheOW!n)o$593FX%ndb?7J>!(Tjwv5>;XQ6C5pw z&xlID3aFBR#LZ>UPZOJYG2FScaTWHp#ZP0E^&d;SVZqsA68rl}9iiTgKAdYQOq^@7 zd_htK_;=UnwInk2i}2C3Se=N3jPMiG9+NV0%(jRMT8<{6o^%hZlvuIcUj08wr=BuX z;ScnB4CT)%JPTXWBdtrO6&z1MHuo|X;nqaa(ngogA0U7Knr=NDt>4NPWvxg> z$*7AH3dizQKI+YJkwVsHng^w3LS8Jwe0X0d9PIoKFCu)JOgmQJpf3gghJ^d1&2rPF zx%*H27Sir|)b6I&mM4@;dpJ#1-gj`#0QmHC^_qNVWVI*4sv~r)Cqe8DVYVZPsLL6y z%L%XR{O&pk^rgf%G2|LoaOj;e!Xv}}c1|tDBR|pl2aRff07dJ?c{rsM&iFdXgtwTf z;KRLVq|=0V@Nv7QHGH*hFphNKLQ#PE*BO(aMkFvfqH6@V)bybB9WDjU=#8A8@|n~U zXzm+|=~QM}1L!O7Q~w`VUlkSC5^WnGxVyUtcMt9!B)Ge~LkDZzrEzz6hX9QPcXti$ zkl>GV?#H|LjQ!X9XOA9Lt7=VK9RYByLC9GD9mk@kyB7Jcs`CQ~+SG@jM-r8SfW}rQ zVH%8Gr~o-Y!UzCVdTkKcOEBBgdW*4`O=&{4$EjIK;f_DEL+HZ=Xv2S}+NUZ*y2b`` zzi0ph-AYE$nD{!3@R$i(maVk8b~L>vsA9f(a5`wV+kSRY#=p-cBmp1kU)&~|wuYV} z{t=Dp?C7(H@!n_&)n#x04bNVg$~FA0duaA1_Nm`lQU3@4tXv8%#3od+@;n3{myY@w|UzyzjCEVGml@ZTUWC{?(l@Qp&6PId?5h@jAZ60sq6hcP-6$$nzs=sO-V zc!W%QVc$dFUwsXSU}86y8A8Kd!a#5m4ll8ZKeNYn*&W#K<}JKYlgPcpvyfl$Q0H7f zw`<{qi^6}rs5dT{Kl3e*YnV-PI&~%>;TPTUxg~&OYq$h8^1^N%J9Q2R;3N-I30QJb zFpbZ_IpON&fV!KxNN`K!O`)SC(EW?_5RnEabwrAqJS$H(Fs2Wc)sLqNbj~^sbQN-P zqq?~Vqn}kmEg!L*X)D~-G09Phxfw*5r39iB5D$2;C1~st%XH#V6(=5%;eYwI5@&oE z_^iYx2R&$A^BnOr! zD8W~h3yrT)iEhDgEu=_{vCkbiQRVewt*iIwIkRT`h=kqG4YXoh;3)_~`8}>Im!;r}ol5`IfY66u6&BTe*>GcPmkG7nXii!|raBQ25->xhh?RmlI z=#SCt@k#|zz{w5mtG5tJ5#ve9&>o345u$_=Pnd>O4H=iFh6WvjR6YW()JvX3;V&nH zWVa$?YQaRiHpZZ;3f>rW$u-p)4+0j@P2go`O8DV`K~>QscnuuSPJh4oGSd=-@Cu}6Mw9O zFX1Z-NAkOAcVO}Z)LxA=-{U+*N4xxQJLP9^t=ceH4a;>UQ%XP2mjvNJHBk3*t1!dG za2VeQ5O&0w9gm3FsD>zMbKHR~7GonI_^@A@X*Lm2KhfU3Fu)4sUnN-WWE_{1==m_+o7^rJM!+>&UEbfnRn0JNfU-&Tj%{^b^%Y{hK3A`Y>ARO;94iE<)# zq|}@8#B|tJMswKrh2y!Vh3C2T=x6E*c4F9)Z;SE7aQLksBJlTXf41MxSE#B>70=e$ zc7On(inl?T+w*4_8JAg*2^plKV3e-zh!vGDkyXjB+v z0CdGRGB#HGFLO!NF^!@hXbe*FGMuXH_QM@+ow}{MNWz1LMkapKxC(yLp6}5Ss00xN zQ+D4IqEIDx(z6{Wvo6QmC;a|iKM?;wXB?Q0c8Dd3-NbwP&|C)~IU!XHqJ`xjA`*d# zaQT>>qv`t0k-u|MaYeIB&?tQ98}Uwj0MD9u{U6g)@iS&im_QZ9Rc;{3MG9Gp^Zk%! z3O%)IDC1>cJ54J`O)rXr<a?HgX9?RSuD z40(HlITJa*ai)f+Y-ff8z7GEgVk7nVvb+uEhIS|ArdyVoZY8+{9F&Sa@&kDvpYWZ} z5p|kt?@j{1O%KHMDC_%3@`BOW264Vw;#YJxdSQc^+czPkhGCAsA(Su?%B_NAuurIR z@h352gU4yKqrcimvEz$@a;sf=4{<3a4%&kX!&L)oj2JOq;Z@|(pg#Y9b!dQlQ8j2o z=zjYfos}nCv@M<_eb&CMn`Ap6!5iF~&3fPs-xl}h_K=Cftu1rAFm?0x;Jw*=79m77` z_i%a4o_IMc#;`>a_hnaq`@mI%TK&T)f-T&4@xGQQeg}3bf$IJ032#K6-1<=kv|au7 zG};*f4+sX`J6szlI)^qp>eCfGcn#k}ksU(&E4ndbnByXtYL9hqVydG@Hj&Iw2l822 zKLvYvhJQkqhan-i{b8ytKG|z3I1|rvg*AmFI2;Mo0RCB06al&3}WB1h?)==Nc7`_?;+bvdE;+f8eaBpVM$x!gXl@0&;# zXr)u|6LkK%6nCW%RJQS)N{I<)hJPU*Vv@fi&2W@tJ+T61dH5ml`j8Wmc-R)9EjzaX zM^s03#<4r-DqKP$-10vl*a;@@r)aL}m7E5VK_y`3LaWTh{T6C{EfSs>j^|8Zs zUVjVG?2-AF$s`P-UA-fNZ=tjY-A+G6l-9@}4{x+|}7_V$VU_UjsBy0Ae0xPcWI z{Iwq3-whO^^*SvWBo?D2fHR+l1ZZ?2hcQ%h_E92#) z`DN4PkaK~GsLrxl4&wde+OIhrlosbz4N`he1Q_r(eJ-m^^63E_b$=6?eAs5YtvG^` zfvR0%)8NIsWiIGb0tIzWKgbim4%aq^C9lrz6k6n(9W}p_9dkWRfXadsDJB8Qwku?o z!gnyPSD7)UA;xuV>ntV7x30d)fO34Vaf;us#ERzCF8k|tbwUILHa60YXFLRA&TqZN zmmTAkOuRkKg+CJ4f{OEK@^1j+OZ5_$_V%t(>hH%?YRyV#rBm!QZs*o-x=is-l&(HV zjTp;6{VB#z6Iuc!=KldH^M_A%*#DAnNkpv zBxWD&w#zeSDDiFA{2Y4^M8em@CN6&t*w}$#(%+)o;l<*hk@mJB+3FWcH@M74`>yWYAdG`(y7`57L3r-$Piu@Co3=i>z3O?B*(2sr#wjg*Kn(le4vCKRJM zbi{;MEExISy1E(333*BO+Zfvn%$8j+=JENZvdD0(2qx?_QiJ^w;w%D9l+RRh&a(97 z*QcI7CVhkK*%be>!5K$q^E>>+sf5HU;@Ku5|JXN@7nm43jJaoC+)NaOSF~ZY`dZQA zMv!u5rPjp2LVC>Y z(Ie(9g3Byvljil4=xgd8|v9qPM*0TGM9{3A%r zw}mAK*gDQ>;sq#S?#|6m&riFo8J&{ZXSC2v+fRQAhFL~9mTa=gCkPg{lj-Tad~h(BJ7y+4sC>hD2rqiO_@2s zOT$Z(#OfSNIqaOX2RWR~?l*Rwow((yr+$+N@KLaBtJ;YKRw6}=wU~x|HYrTU272{X z%K+aB&VM~hbu+%2tJWk8(RHMjRl{v*{%&C>sab;n*Ar4;K`*T&2hhDr@-*pNYM_}- zTM|n@g=WA(%I5ruO4a2Fj)?-1WPYTFSN@75&Nvtvf`L~>CxK4)*r-f*EJl)R|K?Bu zaPvGF@7zqbHGlN64Y=|f!2YJBf2fCBO@1pq)hb{H=-eQAW5f~Grxt3k<7U|&w2BqthW1l zuOhIJSZ#X-VM#s#790^~Se@_AJi zKx-mzuQqJIKBGF21@s0kOi2*f^lI^iEbrDe$J;`c#`6J0{C*ED zk$#^_RN&dA+TR0~p;yCrN=pd+=CDQbPj0@AO|S9(Gh*(q|JidtDKuA>Obvf5SZ^NskE^&^|!E3e!(L(x%9iE;+>1>WlsWzifN zc@h<+x6v8?GIt=!#{rw4{DKQ0qOOug;RPm9;rH}{&bLQAoczdA-`thY96L?+1nNtj zI*6YW5h9ZG#t4KI2M(kEdSSxm>?S9K_vYnGitw~S3h(JH9@$gy2^-%PdtpAQ-Jx@$ za65-HmVYq(yfYH-HV=O^8!HNoohqyd3ErW!-)LWjxST_U!HRE0Q7_ui7uP>^7h+W< ze2x}T0%fH=`BJZtCsj%^X%^npyc?ZdY% z&5T6Kysj22O<#~!o6O;94fkpo;M5uMJoG&)X_YsYNSBqW8AnS>L8%oQt6u3mG8#Om zF&RCh8J%hRh-@EygN7RKvg#bR+dhqDH=C|25do@j9{-)ntrM7zG8J4xk7|j##ssMtvAgY+7%gve51x-X zollG|_N&ct4lAAcd-HHP<)WV@e>tn-w*G|yI%@4E{Z~5`$)}`H?6}`T(kRn+M@%-t z1~hjq!h_X6X#C0<=o)7EM*){{0Q!r_7=`3G)1v}o180B@@n~$RnzO`)0gi3|vwe(( z(an||(D-RsadKKnSR4ovmFY*Vy|L#-gT!e~aRm2shonmoj_;}GQAf1NW96=e- zBQH!VvE15`bSCx~&U}FRlstu}(qj~MgDpPFlWU#kyboi#N701Z1$4Qko?l^eq41$hS{7WCI2)3a!@wxXhXQG9H&)ko?ml= zTK+vZqBfRJci=B9qMR)urj`74A4Z)iQGbvH$%nrIa}EUZ3kL)DedGi1(gC0%!pQPcyw0Hn zw`Hp5NqY^&Dtv~y4a?CbBvb!PuJirgbgjLtGJL!Jz4d9Ro@f|78czmKW(a*aoma}3 zkhhYX9?Ep|t;|$UyFXj)p(`*qIh&QW{0xxnqfj{vP0Yd1e4J)J&D_?*V2NiU4jx0= zNY7)$L)q6e+&?vt4UsgcNE{x8MyX}Koz{46Y1FN0M+fKgF?-Wo@kr81YHc4h@N+iy zu=FdWNGFh~u>Jm=Lu{|0u-SYGZQRT_TGJ$dAA`)^HEt`>tY53yycLC0U8MPKj{zXR zSISS7Zn12L{w;}7!Zlg9w=B%iXT&BnFK^}E#4 zBMr|rbdTAx=L)E1Jp;8r98TY1MFK#8PwYy=ycZd{WT&HvFg3uER!aKwfGuHA1GsOX z&T;oMP)YKfbt&HTXk@ybv;K#mdD zAGV{3DW(R-xvV_lM+e1Tx~Tj)+j@ISM9{z?uYfw=B>(^3D@-F&iIXIx z>ltu6A4ex)RIz^sz#E zy2)SqCqliW5*p_9biBfdpTE2=nkdMa!#mP^N&fi#7W#Ah=MU*8thzE$up~A}UBNnS z$Q+p?O~Y9d!S$xCf~?TUKs1#+V9TY-D4jfG(vEc?(m|0mI+;fJfbxye{sNM?} z3lREQ2p%c;?yJOc;W@c=8gDQiB|qys${72s=AcUl_~hWf*DYyw+Q-)=>r40HNt#dmKi_C~bkl!v}XFH{k zYctxj6`fQt;SUkUvhX|^$e$?AxQu+WqSI~D6%$DK%3jj1PivIsOChHE{Y~UV<>b&| z>s+q8WV5<`^nzXMw1>rg1Ar|`Hu9_i)+9mgKqa}jZI$b^U-1yzJn`)OT)^am6)a#d zbx_(5Be0NdWB*&y{!MvB6Yqu?Uy50Gz&Tm?%r3jH&J+QBY61q4|0$Eyjp89kEh=I0 zL!&LbiD{ltoGE9hEqw~`Eq3Gfl(X^`0*-21n@*@KZ&()aWH{861D;k>m9u5iUtd|j zd}sz4vw{a%y|YeL(Ue2UcbbrsnHY^%L&j2F+Avc_v;Can=YNTTp(cCM?ez(h@3?d2HL-2@?OV9a_J8k2 z$egDbib4B%#icMe5VRn{B}hB~TOuzxr2YHh3Ny@9+hrA6pd3(yfMNY zrHi?Qk|GUAIO{Ou>@$!1cy?bXx@RVWEZQU%#(~()r*f#GEifZ4J1pxcX;`S#%#CWF z1%Wq5F#Q~nRCYvqVOfG3I*9J#fILcZ=J$#*pDP_2j?AbDMAAGU)`<< z967EX2BE3`Pp^9oPXVg+gN0+KaqcqpOyb4-CNrD*iAgadN*1oWxQW^tk){UGoxsV_ zqC01mu+}qs!~L6@96M>i7{(rGpQ@ zkWgk1Z|6HHN}-pJ%j_+6s_bB0wT>PejAX4Xs~%~L?raney~xIlgO}=e{(*>^g>z+T zOu((YypBU3bLv?`N;ctII`6^cs8>$v9APp(usl1%2*$r&T0v2b)2Du5I{S{Z+sS}o z;Uv!}G%$C1LW&wJ+j(|$leGh~YIDaaebH251BxR-p$Z9HEY77*F7x2?BiZC*V?(EX ziM(=^oh++U{Z@|a$aIfNu~=0Wdncsobt`+M%bb)B<-zW|pB@_Ho-w4|cW{ z?~+MrbcL-UC7d(KlJIP3PZ8!QI6B)XC)o-VwZwF{jxgKsS$nT)zR4sx60~=LCescc zXw{3XS5I|U#50+&%ylhB>JaSH`J^kGgci6IJ|^PocNb{eyUUxGnzeYI%vkZ50|fS# zPc?NNCKFr;J?lo?&04zklQP^nzV|&Nf!=?z)fHDWn`ss){dxPS&2G@G=d>O!gZN^c zB_y0Lw}o*ihxMtAIyI?WNft-F7BN0QTunjN^M_oXs+!E}S{2Dh7ncskyoY1w1#_7_ ze}h%+h&{az8rEwc z^vG1&K{I+@I-yHu3g5C=N%Kn5drc>+7~l?8q+4VwPnh%=89gr!hEsJ2K5BN<>YV?M zZCOZ+pH-Cg2=ft?Mx|GcXoN7=#6G?~2)t1j=bK*Q^Y+ZV_@3zoh3akzxc;UOI;V`% zm*}MAACk1h4*b%=y&WB8M5Pzn5J;4-adnGHF`uVLkxUmMi~d00S)sy%R-li)kyKC` zxd{$jT@})n4AJ6xyoh)zv8c(Md_wbw3Y010R13v>|DktO)$UIuwEwV#x4&f+@-bWL zjo9MvAKnQ-9_(VA%vJ6Yp#F}dJ0>81X}b2;?UvE?mUHG-Z79F|&bSeJm~#jt4PB$O zbF>&~A6J8aNTPTjH^z>stAr`9sFyG#U^goWbo>VvnC6qKx5N8bC(~*p33Vs4uXb0; zKZrS^E`mg*rf=fOj*X>EqZaA)C4JX~H9hk4AeyKo66U@MYG3@aygV!81Nu634oz7k zdeFu$evr_vc2M_j`@Zy1=XVCR#%RO%tx}s}p%`2%?2z-YqNDzK4GbyPJD&fG1SnO8 zWP->x{!JH2XobM}H^UJ0kzx3m4lP-c45=@?t`AQp2u56l8z#u=Ec@J!COuo*!pHUc z+qYD6ZS}_^C=h87Ed9qHvp_X_q)ZWtNWlDsKVE_oX2C{A5tQhKds)mHJ!a!$2o7I$ zp^kXPQ{4GdWBpeId{5<(Zzydr!^Y+R(W%T3%5oa3fEAH32^`p{CIxaRpYaG9iT9A| zA%4=~Wk?YzM{ABjqeou{$!8s+ZyjFnq7vN$Qt*@Jl*)Fv!GKLs=EonG6A>bjWS7ZZ zZ1rULESvRnq67mpEX zJ83(8X=?uvZOo3(To`=V?*e{FJ<0bNx`b*V_)m2x%*8W|_9t~ya`?sSGXIg&BrDM~ zmbbO5r|@ZA=hUSW6YcAmwAAD8k(Q!PKRL&{4rvs0y~ZZ58UDB6pQkK$nc5CpQ< zg2B~uvDQ5)pH>$`%Rze14dnzwP#fySRqKOOcLr{=K7(Vs_8-o$4I*Y$!NUY!XINz= z`{Ido>Levc)K-fZkrF)@-YMl5ll7R!<566A(*INjGBNX2xS=>?Z__S-wzXhbA!I@5 z+AuUY!4xb|2*)N1`TeEIt2{@(!)6wXx4%J(+AzEj_aKI52to)%knc7m32H*iIl;G6 zOj|mF zet_P`ut;aG{QoVzBzD|~DB<_4K za?!EWk++p+?M$tsEG^ypNtwRrdJVgr5L2=^m5gEwgBlWKAA($sk#r--Egb#}`8ou`UzzTB0M^$^)4BMd9yt(%r0K=?hExBWYXVNiy(H!)M30Mep&7&a}??)S>Z_{oX_gpwzJ(6w|-eQGS8Pib2@qCZh5C+xp>C8doH6( zx*6dWX6;ZqqtFHZ3n!gtP?^y4UqG-{dEX1>WI1qF72OJOiWSqW9(lUucMnmt zzv1mD$`5Ty0Z(8;E_X2o47eS z&ZA$0A-Mp5etH51P-5CTY>q4?UVvf?moK4L=0txA(S-;Myxf5H%?}!#+en~xtTMB+ zii{MUa|!*tjOL1x+~03C>Fyd`l{s0(EvbvH>MhrE+V;Nn5BM;n_x9&)qR#3e5>0aE z8j7077ii|`O!sa#X3ecGP>2Hmt!qOt2*fw{G z&LH>fz9&dQXihyzU1`f{0py7AS{bi|zY%T$zfIr?narSHFhBp*;Jmig8WA2O2p}eY z0orENcoOWRrP!b3(u*4x=>f)3 z?r#?iE#y+-<;VP>Jz#bu(_80#z8Y#Lw8|RXrA)BqeDHP+GYIUqkjsW=^tWs?=g((QQo?Po;G8;PSm7=M4s6Lvt$6T%*jvdSWQvp|}5tl3>|k zuR&u1Uf`vw9rgSG0pKTpigEmm=zg&!I&6*KZOy-R+`gh$xN&sO*y{6sgJQnI*V~8o z>$P-_cn=wSA*s3QY#Y7YATmaajF)rhx?Jr+wcXZB-2f_S%fylcDSd?D7^6sUjl9hL08y%{Z0v3q#@5+d$_4XmiR`IJT;y2z--txK6HF z2r-7IRKub+J|+n6DzfgENoli2aM4x#ecxb$Q)=0gT-u@fB|ON6zTKu?CJ5Inv^P?x zCOO$~H{JHS*~{cy)TGHYgAbVFZoJ}KxnH#!Q4XSpq2IbQ_ac(B?f*79uf7S`R%RT; zf;p#aw%BiLXo#PKi0Ht^pbd{hnFy?7GpQ8D-JwBq0td`lYw>W3^&nVt)xocS78C$|a zyaP6wBvzI= zSfoaXmSz%+X@Z79)SpJ9kPsgd6oPdT&5F0buyNurvvE=18ippTz<*qXnI*Y-3<~rE=r1>>vcS&0x|SK5PaO#p&B52L~8JKrwyYK?6C1vlI$UCalB#( zdNhR`;3*={ZSMH*y}Et6$bax4bjfZ{Ksur?lV52Dw!(MmZxcgaVtIjjJE1)gx}>+e zAuln#e)htC{z`X69;gpVinGk*RM{*2`RkV}w!k>VGxWb9y|mC@sjsX9r{MfFw_O2{ zzR+J;uAl>15d37fxdT}c{UnWYd(R=CKRi~vWLFx2weUy?L|A`2dU-yhz^~IgfqIPt zJE3FY)+w(P1AU<{Fxw2bAp&8cyy$*}LGcc$m{DVB165DgxYKpVokra-cET@LlnQeC zw9Eurex~I+>D&{{+Pm%HhQwUop9aJ2Y zIC6JP;*8xgu_UrRXO~C>kaV#H_vJ0erF>)pu|fPA?97Jw6wIL{Mo?_o4 z9t!FRCzuxN5_ZG03mh(*8)bEt@6P2t`%WHrb_F?Re{&7CuwJNdSI63M%hlbEQ4I-~6rPtlTYUyT4ubSiOX03FH%}Ka>x2Hq4SbS0zTlB%QeekQIghp4rV0^n=g-bdH zts&>-V%`ZG_-h?48KS?=fug8Rt+8m>DRKkQ?1YgKoG^uusrO;)0*CUuAi4XgzImV# z>Ij-zIU55){nx1FVOex^yaKF=Gy~`n!XOLCYQL&M8CNS+hJX<%#Yt}`{_-Z;OAD&%?YS+#!CVK+rH*Eh@8tgo=*i5&T~ z!d%;~@0;J18TIYv0&VnfcG<3{F@?G3&}j-*0(-+D-8Q3!0iUME>$=h`2}zH z1)X@pG!QB@~UPTQ%yPL_q8VC zyTlp+>alZ-Nqbyl2cIVp_*5Ie8I;o>Xk--bQ%%gcG+3l`>9|Jwr5|cNx=b+aV@){U zU}x+daAkZSDbHAN$vAY=uGXe3wOt$~n80t)bS=rs$4}+pDjlgiWaN`?R9dv2Ol{<< zOs2ld*C+#?Gkth5NlUyG+4A{PK@HL1ufY!r$%vseo<%0 zAAFlIcS*Mhwwty~j>#B1aG9W4DQZ{Zwygm%W$=t(XAqiI9!fpRO*piFyR}#;u^#o9 zAZeH5pb_BQYfzg@tesu|@|{6*mmELhY^gNjDLqCM^ZqvA^J8JzcAPOIfGFuNX4(Sv9WuJ2Yfv|}1J9*13sWI$3o5xMA5$-$v!&R;^ zi*Ts_%WvLafI!L@5br1;bnj(}w+|4U^wP>ZsJzGdPCR+FwMX<0g?J_0;POVxo%)`x zxC<~=d&I{%WU2FhskMWDC$!xGSQ5VgNUNgWliY6`8T+Q#KsAv8!S&}-5NpO*4cSuY zYvxWZ!>r2&l)Vr5LByOvXW^>ju>{m-ZRjSn(ce5~=}b$bT|8FHj4Y$&JSO9zAxzap z+u1sds#G;tSMbD3T^f551lJXkIU{%JI#d-rcU1kx;CkTxH>3sgVWa4DAO|_!{flX- z-ocZA-t1w}TaWJ`y&<5?EayP1V-Wa^B+YKh6IXql(n`J+l>&^azax7D=J%kIlGwSd zEE_x~2cRo1m2QRylrylD525CVk`wx2_8Wg&M>49dmt1S7(##$YmJVE^Zl)43o>Q_&m^_B;^Ix?hOIETJFGH zU0>84x~9OQ>RehP-KH~I<`h)*P1~vRZ^9f7T@&_c89Z`Rcb%l^jAC8rJ7*-@rbM3$ z(J(xUO_p}hUt(nR^*&`?j zFp)3kHv#h$SMY;8B$4}=izz>MrU;QAsXqXXavOfaF=LM&FPRe%@^+u9idSnX+FKQ6 zFUy`Ekz-3+;nI{tC3+a%e!n1j3pwAvoa=5Ad3H*8*h4(&|1%$xTL$}6g(aZ)>x&fZ z73_T!9Wj=>n+)fS@r)>x-f)Cil%h$|G&1)3-fy;OI?qS%E>*SX|0tEK=?*tRMo<4P z3vwA~d_cAOm=dNc-kXvxe>OW79yEGa9$6EXZrJZZa?f*e)PMWRLurwL)s(D@AtQ7zMt-TYi^{e9nnA6Nl&Y&h+nAi z0e~zIVk9!TN`H;dT1H!QFVDi2He7uSwzzoY3O^WQ@G+aZRH!1SxUrjIgu(2H-`wdl z(9c@3zyAtH{b4YFniVAm#*OII8t;#Qc{;)ccDn1Y~BKSATXrFx9t%yQ6QgF2>at9(jb`AzloDd z5p6hvy};B~xVHy0Ni6VfMW&qDB+-kByBDhl&Acr#{j;8IZ~C#@`6=JoEWO>KIi5h2 zE&PKJbs`0SY3ZoX6I?oFw0|G(wa){b+~XSA!Y@N|Ic{jCe)Y7q2&R`fr%Y{ z?;O%REw?UKnIjmt0)A({Dx(bkc-oFsjsI#Bl2?nT)j*ds5dVnX$qYW`*r?1xpaQ;B z>oixZ=x8P*5@#964C9w9^M^k4Bc@X`a#9PYea`wCdAS|BnYR~;x-HHZ08zENh&VJ! z_58Y@)!0d!>GytpPxu28K~!^UWbXqZgY$)a!A0SkLz z4^wToHp`UWe@i9$z|djpTzk8Jtot_UJW*mt@YV5-pBSNlzC&UkxWM&jsAC{xIE8!i z9Gc>)hJ|lpe+>I74oMIzv@V`5x**L9_rMjOU*-<-&1c@iTVT`cZN z)kW;xuvC%lHZo$?apOCvu?65d^Qh1Ao?sP+wN&S*(*HD?noQ@FVJ&PbSrV<4te;9n$<+cnr!jk#`8T~21spTSKQah?lZ-4ViXb8r-Ca_TnOjB zNwnHk2qqNnUq%rQ9Dw{93~eW3(g%AbZHKnxtWH)Jan#@AIho~px$bM(^ZNG&TLfwi zCbCVZzZqi@S#KDbxYf<>sBJ>U?+nJFYdF64Vi`$CfJg?2J%+q5y8Ea2B(g_ZW)OiG zu(Kl8e(VEdbB)MjqUBFvGJ_HvpfDKf)SC&Yi8sZp(_a})V`RX%b7&=P$ zE0FLufSn)#9g2;H*z>i1_#F=W{-oQd&~te?V`|z=i)55H)PA?!n6=s{SJac80DN14 z{VVNRJ+g4Xd7QG`DonW{&plxJ#AC1yK>W1F3J)`pJ$RHneLalSENMQZnnox6)qM`9 z=Dl-!^~3p%Nu6vhAxm{0kk+D0{cX4;f@yuhIWFII$i7&+B%+-*i2U+Sxk%h!aBhW- zaiW@(arP_Fg=()*tGzGYxYOp9-vNgEU24|1`wxK22nyOq+^zFS^x(L#Z+esr5SL_b zhWJM~*q@3v%=J!rWZDo+wKWc>)&E5s$fa(vyQ)xCU4MD`yU8(N&ZczrwvBbJ<%o>0 zVaS2{`v@SY<#~rQDBu(4tCLjMMd zxfk3sKL8u>rKd54;N2IsvjT5 zv43117@KVI>rsxLp}OhUi5YzHc-AyW|LnRq_{jajiW^*mzY`wv@sVQ*i;3E!Hter? z3ZJO0@n+?Y`dg?W97|j*WSgTbhcC3u?!JGsu_le3G`8K? zX>2#PZB00_F+pQBww*M#ZQD&6G@Iwy-E05vd$7lIHrMxee{@4ibYCL3Q*!(=zp?FIi>V9zMS)deKVsR&ggC3h5^B}Q zsC8&()lR7v-vfB?tTM*I((PjyG6RjjpOA=^WJZ-C73AuVZKm*8uLub+s_ih|6|9}0 ziUlYv=bKnb1{zsXG$MN=TMJ7iI z1^Ei^GvPTN?U(!M?kUb&@G+%cDO3%Hj}+VaKo=~}Dv3`!f4O3lqk-MFH_+*&rn}cq zQNx2iG@csWy0q`R#F-d_#0Tf|=}*^CgE+JG+Y!*_cqk*f^xHA@hxh|4P>N>xXhO4g z56!)WtH_)@%r2p%aooo`HmIR<$@0iydTh%$v0E$%*n{;K&FU`#_mc&~9drDv4Pz+8 z?t?J|+_WOXEQnyFW%bi%72YuGh$jD%wTqL(t)FUN2&+;|P}`+JQZ^+HgG`a@(zg}N z*BI#k`7v3~dsu;mga75|+-Sm(0XI9nr=w&^;3TdM#o;kSn;u)_2NS7QV%jsG?7#Sa zB9@U`&GbY&VlfzZ=o0MS6#68d_UG%ZliW3u8Nnps&L7{Z<%l+=A9#OuL(JxC(e%+}`Lm8%mugk*F8#w0}z;)}7EQ&&yN#JGgQcCcU|>qM8fsTIFMAwj?grQT_n9 zNKh_F@>e#u$F2W$fQS>uHA2P5_{?(IiT2rJRcw0glUPh#1oxl+vP(o!r)Wb$`t<1r z_tPi654%M0Mm3zkM?2GNh(O$2u?@il3E|bewhM6x|L+;&)WXjO{E7|ruY9K+j)n~} zs5rSPwG06>m1b5n-dLrKo)%tw`V?T#C99QaJG+4#+4a2Lz8Adrv>S!e^%G_02Aqon zMGXA%_KFnX)iH)PL^vcdE|GAE+Y_~Wqk?%C)HPlk@SSyiFn>Fh!t`tEO(d#DehayV z24x2wDLv^Bsx}wnoSqRpm1;X6Pq)*QMRzzewRWZg3%NZPtGp0za>=c-t$d|8er+_~ z$C4L7?!l?4%2;A_Y`-x{#8ruCWwuZU-~(zd5Dt;l#xI?54wSCz`~LJ*YA&ZNFm02m z)hmA6EQ<_JE&o0QlBcr}>deXB+RE;pA(aM+u=!#2zl?O4waCP{SFNoE zmVX7wvnHDe3G1v3VEMt_Gsl z_(OLRu}`q9olymOSN5X1oXUUac1OnL(H>sanDxqd(9T|R>@^CCTSwLPdd0wAay(kt7C7qSbg$m zDI5TbW9a>N&|pQd_EeZge!M@C2e0|X0d5%K9eIB{{Ru<4Utc2kXomkTR3C5(DWNeY zNGJE^`;`amWPW5+a6qmN{fhjE_5>Oe{o4WcwVT1nwcXa^RIBmd$4tRv_==`PYp{|V zO6iXYhr`9kH|#z9&T-}-{px#rln;_GZ=$5MN;q5oPAM_kQ+C>?!DBo$naLZDn>vR8 z3l@ds9X2Xo3wL36^pmcPFQ0*fUPyV&*LbyzAz;ynX-A4LcdmGGC2m%_XG83C7m=tf(wZ+w4{v!Yndql7%7_G1Fg9bq&PBJp;s zceLq%&^f!jRA@nNZO_-PDY;htR4oLiL;ROKI>?^ucfVk6Aa4*tz8Fc0s)$CuMa&yW z!C#^j?&fmLU4R(TksAmGdAV)JxxY>j4$7})I%YncW9gE4XZSd%Z{F`7dT^IH3kc~Z^>ra{Po1dL z8_S4#@6txi^a3qMU#vQ(<_V?in1y3@mKiP^P*oObnCLxWbzR1r{yf)S*FNZ~e2Qfu zb6A1szs6$n8bQwJOU&N7Dcttd$m*qOt-6l-i~@udDdQeZU1AA-9ysAU)SL1s%eR(w z=~S=A*iqk1-Y?&<kZ)Ld;ctJQRZN3DVc%`|MEfV3fdT7-n_X}xUwxo) zSEOR?0Y_t?Q7{s}a#0)DWAi6f3ri4+9*w!x0E2D+u}aE*0mqA7t{OB3xEs;ONS!G6 zxd66vk0>1zMTr<7K($zxLw;SNN4Q2W!X7Prt@2~Ufq-q0~Tbk-5vX&M~ZbK3HrJ=a!Om`FB^WCb==wdY$J zwO4Fau1*}-B=b6Sb+s}L%981p@UXoro9%2lH7lDS`>O@w3b+G=Zo>x=o~u3w2?F)* zg(vWJUS>)L(WPTixy62XH#5Hh{7&-z9)7 zFcw(5am@Is5~)&Q%l9j-FBdgT>?NQ=!*Esl zW6we?@H{miDa4HD>A_475GVkO^dO6<(ZXvYPJIlp^uq@|I5`q#tz4(K?}Xi>qCMMy zb|eu)hdl}jNnBidUi9RS$`?5z{3Z zvvS5wWTR>iz_?QPOF7)gx=!=Osp17y|_H zQoBs}&`wA7`TW0@EqO+XEWNoXYblL_1Q-cJW3krTm(Put>hv77NbR&Jh$7i?ay#Ua z#5mcroK6@GtFR@eyBO=nmR_wrB0HJ_KwkLJ@A&{Zpl{?9%{2^VmXc`Dc$>2lhR24L zHdUP6FdJd}PT9Fj9{A2|TRqj3>2pTr!>g`fvbrdQSM7n}?Z9YpW^XVuoJRkFsma*usW-cnZe7{`jRjG$$5Q*MMWDqr+_nOT8^ z?j`9#;~wV_h22$qA2mE-6-Hg`m~^AV5{6&QLe%^SUH8Buj;Z$Ym=khLOz?csjd7P} z($1*H%*S6t)a72$b8WIj;QHE~vqx*7(MkCSh)Bl8vD*VA-7RyJ2tf=T#DT|KKBjHE zhmWpq_fIIu?8E{%%(crB0q-4pPKuJi6h7hgAJut;ygNXEsu<$pUY?fJp}YtSX*>tlTq%&f_`I za(hc`3YT8W{9eQk#x8x(@|HAFAg*p?S#-=An0tUQKHg+|s@XBnt9VL(taK;OE8zvt zSQ`W_okCMyY5ao0VV2~xnqxeq7WMa&ZUH9OzsxS<4!^~A(hhi#EHVQU>d8>6b&eC1dXxD`Ef%L6Gy9~Qut^A|* zI5LF|?!zqjhvGqhk9nK|H^ukZkHxR=;LCq;f;Al|aKWU1 z{$Xe|XH!7YKtS@mg0Hh-iJOlop_n26ZS;$!;T^$WX#Q>V{^KrSA2ouJGz@ zL;(*H`(x0s`Q((q(aU7((fS{+`#n@)tRhVG;h6rO2h3Ebe(}v;^056_4rHL#qZmK` z9>%yA0UJ$F?ADqoP-@e|_nSQ{CSpn4H`9s+_!?|in10v(n}OdoTWCf}9{jiCT#%VQ zj9++11)cDnr%0dE!*p-kh>=4WgKL;1a!BTqzeog$y5qY~HLKb^jzYnbXPut$=GajP^a5cskH2=tLmLDqz31@(sIg*@i3x~ZWn-rY$wVq)$7=WR_c|K?4 zUM2I+J|;}-6}qBW-5$jDvqm5ZS4^OCL^bk|O-r?h1IH0wee#LPwVC__n~Y3j`X55N zvd1adBT&+&@YDCRkn58(Sv|8C`iiq{5SAh{(BE7Bl0B+O7RXM^5|S_{Ao?G4SA0y9WZ@ zK}PZijQ=|JOzswQ{+n(8Q71_Q5eSn;=K(wyHksw3Z2&S&KdU$q2Ij4cxy8 zk51u*NbO8DOsnFpTK;mMA-d>UFPoiSW^reqB}-ismjzn&2p4n%)9X9Eb=9O$)63kK z#a82@V=ZCTtsitT(^Tj;c4i-V*l&6pb>5pcQ|iRlWdtjPK|9=Zq0c&dzg1yvrwDk^ zP_({E)+#e_y33>|aEKIS6FEXl0ApKVlV0*h<6UDD$6op_!?FA4Y!|RbPnGMN_NS5$ zkfaM2ufuCC?Y2r6JloG7o;Q2!>@?`;_b6Fd=;%+lQg-cLmd9#%nMMn*kP8`4MbV8z zZ3oQ0|D4WVRbRj4-+ptXp^^hF+vECgA%Hl9p1CxG%Vi89m(aueI1=OyfiOIv)%P^? z{>ko;qBScxs2@Zp@-fSghONzitDr$&o9%X9(syG%9;c6q{nSXlWzMNqz9vzgrotHk zAczCG+KMS@KO*5F-ZsmWAN&rPO79E$%?gN|N5cik#y9Wt>q2#xv{-imb8B4)%JB8^jgomk#rd7saUEKZDX0Gm)YU^137H z9=rYbg_JtJ+)gQR-BW8#6AZ_XpG?$%&>I_sTP$eFEK9FTG9V|7m@0|`I3~juFj*8c z6!3DtUZ6^2L`A<*G=q?g>Ty_!X060q*~cLE6li~Xi73XB!o(JGtD(&T_}NCwMbMa7gVbRf zZ?4qHVUO8b>Erwz&l$xn%;*@+qt%$#Ew44TGP0PZ3E7{_7Sv*#(Kku3?gXuUS(>4q zlyy3LTl?Bq7gI-bR;6pL1}qo%OkdJ78uPBSAO2#x$(Gqil~SLxGG+ScQKt%wN;ZkV zPtD%(lHm-cUpfY4OrYqlpm9NrOkm4MZtBuwdQv(poNDwl9AQ#!q(iC8mM`EP^0`Iv zYVYEm7!ab7!r*xgk6Fo2e;fB{2o zOMesYkdNX#lZMd5m}4}{1<()o;%iArF^2R^Dc7U+1hMh5|CR(AN_koh!*bK#YMcxc zM+15N=4*xa7wnP7S(ZkGXS|7=EyRA<5@9Nw&c~a|2ngI)*_@eEmK5f&(&(8NM2L2fCDHy8LN_<55U?y#$vb3BjahNh z1Z2D%e7JJIHo@gAQ217fGsJ?Ia%0UO);r*YdlTdxL_dfef@0?IazS)iD&f|+rhaA& z9`jjEU5do9AQiEIhSMKY*Q;TEakN~OiDIKRKtTCHmn{e}6@ z{ifsZ*DEj+>%R|?6$nGqoXZL&1OZ$r#UNB^i(D{Cs-H&))iJ2l@G97D;8R$tIs%wH zyCSOb)o&Q3@m1=qyR=o&a+wjQiL^{@fUbR7sBOCXJz6(+-NmY(s?4~htQvM*>a`EE za^VmKRj+x(SUGK_*?Cspr%~K(8r~a`p7(qYwtK9!Z_yq%Ka8kddL?xIjHgx%Gc@7 z&kfgtcfO2UmqaqNEw)zvMWSJ0R?^6>y+xn1>^s1w|FhLr6My4G_NRVDF=ESa zfbK)$Pn-E$KIi}k5^-(_-eQuRCzPKwt{7}sbVVPYcm->GN-p;kTjlig zhDC;!$^}WR?bMP8;VsYx{R+DFfHl-3m~7uExJwe1{3KIK*>_GnCh(1tS@zwWx&A8@hOrG+nQ_(wOkJ0T`_#tW{VZW&h}gs#n_CCEH$U=~#u6d;p#GbOiEJ z{NTVE0!3r+zsKAZE;SM2k1^Nt10xMTfps`PULgng<3-|u0}vsRfZtu##4-Oaa<4?r z!p=3MHNeQgPlnRKme}vcgIZ`goqnif3XApXjeVQ~Q+1^ktPMR4x3iYIZu{t2;@u5F z#65A_z#ag&zK%3~JMRW}uwbM9o5hs>(T}T&hq(dK27wBi+=5z7%+? zLyGaRgw)yqO|y_1APuP8hyh{3##k#gp_h}jLfnz4I?PGzd=hj63Q=oS=L zr&aAVEmk<^^*+jPn5T`Vx0NpafW5 z>zQ5;4RPZ_;+5yK|Cmfr@6u*Ib58)<6h<5}#4K^O*oC_Rzu`GHBZnF7<9m25y5hGT z>ij0fO+2nlGt6ud?5*uS!-4>RLLb!60@B9~if%&we!IuOvvo3FTesh?S* z1Liv04EgSXrg-~J+?PE2 z>C;2p5V-L)cHcBe6R=%xHgb%#F1K(746d&YxS^{h+Xxh{t_7+{KqV1x15D@O>*ApA zG&EnsN@!xJub>eJeoE2Mc_I<)hBsq%1h1(XPd&(gc%Ggx=(}Lr?&`sKTz@%G>3yN0 zZ9!tntH_1y`(hoeQWHv-(znLcXSDqK9zMlF;asrTqOHC(#-|VUS`s5E$J-Q}lUx9h zeM1j1sujWkKqbntQBpms(4{7A^!B7Net z^8Kn0I|{wqeE|Jqx;L{BP*cqj!3ba3_ikK@P;u+h{V;0jgE-q6*U2B7^Q|6 zj|i7c*(*SsbQBKv2g(yOTv%{z4}^kWU{r07 zK#rstYJq`$O?_0zbzCxNd*Y-0mlld<7D`|^&mZ#Vv}ate#Hd?pnvoo@9tYGGvml{J zoZ~gwA}0Vd`abQi6Yki6fK3EhDGbwIeyhZD-)s(vL}KOye)x9>B}%z^0~R`zKsMgF zk$%F7K7J`Yv#^`SRMbw8K4+3L zP_#RF1RpZ{KA`xj5zpWDqFfg+_;AreM1j>jr4>EA6+Ch-SN^^o9Wj5pTUMG0WyQiD zB*WEY4fKRgLX#^^8S@)|hc0|@^y|HkUrRn8c>d^E{^vilpXC#Z?ke~K0=MI}C$PS5HbvK)O zm^OzqtL`$3fqLuoim+J?6=rM+rHq=I!ZT3Qcjr{2Rb`e^XRuZ=RF=v?s5U2UYb%Sm zlR_#|r1q2w#C=o2=-Vlmp2;M1@21!il9#gxfew8BEh#t^g;%2MROU`Ly=Ht!)H*BIps-hjMSjlaoo!>`9rc)(hEh-l1NGPP;NT{lWu^S**pK z*H!9qk>&Ecb{<+W@gL=MEeJ#8I5x;!Ra33`X@oEqQfr0tVH%w;*N-|z#G^hsu+iW* zRt+>8$g3tPHG-jqDaW7HnyZN|;rNat;8D4Y_Tc?^Y7s$7M?WpQ&UDHLH`FVqcQUS0 z|30_${Q_C6jT0WkWS`M@Cy9aN;?jH0$+^D5KIz@SPgEVvEr4MtTQ>~6E!$S?Q?rZmMv%t$IWVNgYuqHOx&Te=VSts z+3=0ryH?m)KEbV)m=Gc3#g=X5`iehlic2LePM)NB_m(YI<^&g-&hshJSfiu4!2p#x zLq*(DxYqH}PkA*Klta{%+QiA>mX)XNboXV9Hu*Boka}ltJph;6&t=MVj#uaAS<5FTnx; zViIaH*e#6pG2c4Ja0J6l9X6sr5>Ym%u(n=81IU|O_EQNsLKp?!{bRU84babGD{awJ z&k%umgTcb_7X?8V3loMe?w1jN=I?BykUHn>l$vr3!lD7v8}lC>@Mj*pxf$EK#N-Z)Nd$>)m9nonByW(P7RX z7Fu#{QASMF-b7xKZy!r)oZwn?Y{xZaWTCd^oq5=;Lj;QHsp;l(ueuFRWE^xLM>7sa zOUM{UTvU~-scOG1q-Ok*BWIvZ?jPUlt;3JVIA?a7^~#LLQG%V<*E!ZAuD_&P=h$u_ zTk3jApO(pBzI-o-%4J)n5wX%fg&F!;k9F%!8KJ_>>HUlKjII8PJ&D>jh9;7-b^E4U zE_bAxfuekM-yX-3HTMh8BHwDD$5AxPeiLJmA(@9)hQ_(q(n}kC`(({l!H`B<$lkpq zZZ7}HNH|%3YGR=uMf!(CJKN<7)k|Iu8p?GrMddx3;wB;$;`bhjGDr;9+Q46A^-F$I zdavcIXVkLn53=8k-c`RqCc!sN_S?uDl(Dg$-y9Cr(}EG%3YpFfrb~dp0f;w(!H28i zW1+rW_WP?(vD++utXTO(`cD0YCZya!1<5tLk`YnH4EGak(kTy~d}BQM3GNZLSLk6n zu-zv2sK(TNHq>G-s>w*I4~%CbJ#33wIdszfLM9p=R;jALJ)R zgpY56`T$Pkqd)*p8NqxaPzYop#j&#ZyA&k(ywho}h8R_51M0T2l8I0wL0J76MlcL3 zuHfDSIDRsmUp5MTQPR4pta0>+w^~y9Bq8PK`iV6(JNRO|Wf#l6WMJY$I7$dc@TmwC z2_O@6!o}I`Px)T;I~(lu@dNOX$~#BZF#bF?btfx&M=Nl#@Fnxh76QlCExhE~nc;rJ ztaIzQjYRW`^O{0q?pe~CouSeX8Psc?{@*7Zr5G1n!>R6ddfu*x4sgBa#)r6dZ~A1` zT;Bn8S4{$Qt9AUlP?rl8B>ReXu0C*ETFM}tL;8`T!a99Sz*GWJZ=+OBpD4FO{79E@8z z!xK{~szCnh5YKJ*H~Gdd=}QAO%HWuo-Dh`d-xeu@P9vqO>2Kf`F(`Tx6e;?I%exab zS8+k{bM^{&4IXh{QtVDb;+PVXFe%?a@C+^_Auzgr?Gc!vP&%Y#4b&?6GWg8qs^!@r z1rhLy1ll)XrF#cC{qZn85UL@0kKjy1{^PKod=)VExIO&nl>3R87LXJFTABz?UJDg^ z%s;sYY5Z089Yb+jI#ML{Sb|?ddGA~KLcv0CfqJAGcVrL&H4##4$p{m=GsZ888^Fz; z)Q9L;8)2%BFD>DE-5`8xARRc8JTaGcPQ|9kF)L4TmNi@(+dG4`o7U&ra-m`=B*qjG zY@){K^@G%cz0a0H+AV2FMf4T!z=)yfzsIfuxPC_PtN6d;f8Gfk5l{g`1odx|$NjO> zE2_AfurS&S6i=CYFBz)_Yf2CTD*78-vxg0jcPG7vCZH?AAul3m=GQ-bc$XzQ1g;rL z=asdMmAAvp^sMwNp)Oyj_lpD6%M@$f zIKFH*-l%CmT)0{r7|X){mv`E4hX`I#X!z39g^xhn?_z1B?CUuDFEGOpVk#aesYt-T z$1Rf&%a8q7MsJl4&tCqq94YGMnP90NC~u?_sBf=U&f%1_1XZ_I zwqPePui;2^8!Y};VJ>Cel_1gAvd>6>?Fz*M7qi?eYe)T-*+~c3AVG&@UwO$z$Zo(; z%nLQ`gWJg4uUk?Ra>d0jW{VUTh-F3WSWOmWxzSkN|jR_XZI_)2?@Sbz`G+KBF< z*YM#qWM6QN0Bg<4g8J|+3wxPhewrOYjcOAV`JjuUM>Umx)V$l`;Dw~>?RTx z3(nGNqrc5wp6h{gZ$wkJC^D8mX1}rDSUD55vnKr@aaej#vn3-?EXFtiR4%0*it`Gl z%TvVMTe4w;NlJ=mBh+T&x4CEM*lX{{Ii&r*q^In}3-YBkVKXc_J10wMh3L^RrBCK_ zDJC#3+hC?}nI9ARsL|52nz*awL?qe0E$*1NTOW?;{xSv9__n0_)$a0}t>mx8rZC_f zGH}~X9!QfRflFZ!R^q!%t1@)5=?y)rE*L(8P&mVL^~clyXwNmScyNBoF~Mfg_nG8b zFd25Yb%MxkEZ4tAkyVLacc<&5P$8_iBA|ZiB&vq#-MW{nT z2fI^-D!V@Ls}<3^HkIELfRJqFp1VZ9a!e-%Mf&N+B$o*oMS5+f1(EL?OrkkICt5lO zQ%d%LE0x5$nYOaUA;-Y0wA{G@vkP4j zgHlt9@j1dLD?vGJO`*a9_ElHQ0K^UCy3PnHei4GEkhi1;1ujRu{b522?YOjM9?8u; z-0Hy!v;#|gG9l5w7A@VEh|PJ{3cYJBwVm3x3CZ0;z(8gU+p=om4dFYgSboVU)W&BZ z-B%q9n9yS_F_!PO zCF{CajRWpP6=6n6kTE7N@6-;7R3ww-qrjG+<#BC^$%+Utnn!C{`T~66Y2PBc`1ms^Sq40iH9#CuJ*|_GORs+_k zu`f^PPta%&)o8O2yb*9;++4|@*8ap_kOOMAb?3lRmKDmWKib@=$q`m7Qo*WaNl98r zSV)*z*ieGi3n)42Q%O&=%4_fvz)kF0XGzK_Mj}$OKPOH+!DV47Rk+I7p^0dei&e+? z265<>>nfmEqP9et(wPbxSe`VgpFnRvIaWZ**QO~n-;ovk7ModGHn9{(J~4YwmZGMz zjj}2#GU$pezN|*OyhQ1axi&MFykCt{ZY)~7P;g=j6xqgF1TsI1g%o0=j%AupxYe>M zu2D?oeqM7sAcUo4Kb!KW$WiCJGBB6nXH-e9NoSX`Eob0)Q$U!68O} zqLs2F*($%yyMG}sDLob_qdlxjTP+ZW?H6sO=P;W2x-=bwME(|?4lyovORVdrB7}dSg^Cm!JZNxzC`GGpbMLAn4K^N3 z#)YDnVB0kGbg5e4n~AC)V+Y2%r$(F{Qkm7y;^B#jUFL+u=6O|_%ah%`&ZA348mAJf zViOunMb%aCs~nE%3^LcsZ5GNi9->%*Mjq=8ErE~PFPwKayi?$JiGh~h#)WxA%5@R_ z;yQ<@`!c6cd;F`06I*!f{v0F906FrKh6n=F%)#=e#8N%$#)-4~-B_c9~7c3?ynzmJ;VYwrh^n z_dx0_!Z=OQLB|RY_P8>qR4`7BwnM70E3TsS_JqoG4S`mr{U9kTT<8?3N*4xj+ft@x z=aY;ja4XoTjO)(|pNt#csgT3RW-9f{U;9{`A{UITC9=^xNCTg-<{DM(TUY}-p9x{* zueZIc{9k@-HK>x4SPd?EjuK*$u1S2Jt7B#Ofmu_#e9PV$Ia6_2@Kp=Lc$l1-TkbrN zBFcAZCrghy%WaS7ZW8vA$g1H*$snz0^L_eOU@jHT55QP3#Ufb{+Le1u277z=XF+bu zTI0F0&w5o)tX@NMcR0@}u=<>aq040WCWSck0X~7@dKQ?y{1;cjSM*L%S*BccwSfG3 zM@4wN1raHt@Oz>p`nYaQuZRy(e@#kE&m;@vNYI`mwCw(GadAfH&B3#8LkSiD}5v_)TZClU7LG1ic0r?;{eN46fB(gJ{uweDN!wMqU zq4%YL{j{L;|K&qjiKX;`1>gS7JYm#^;)R14Z06>KL`DTd;~+ zvSMUK7qZ;RC7XtYekYZp^jlk19PF7#mKuYl6+71+p%~9`YN1)_)ANCEPWdg z1%&Or!!sd_)z+=R>I3g+z8FGUcnq)=#po1b6Qu0mL2zW1iBL%mGyem6SzW3i`?X5J=m z?h7HR$w6u}B0J?BQ&-zQ4HPXUtWO@R<+tWUv>Eb5Efx+d+UBQRSHAw#CX{7F>lsj) zi&Q)d#Q@`?bdr8AoXi0OkW~jC_}R-c z&pYtAceod8JPI$#o+F+nUYO%cl8;VsjX3-5ET*4KVE~mj&FqPgDsjOo> zSMRcmH)XNGYN;Ir+UfcG^u@QA^8uQ%$V+_p4v{W!5NIOX%I%g$&Ae~Os@qIes@0I~ z0>KiK+b?~aw={BS8zwRlMjc3XfWSVc{(+~TakCjTALB=2xjqd$^xo`*p)&PzhJmX} zN1rU2!@_xx(oO_+$}eSfP=x(G9_|H0tCz1jZoc)3ec}?3P&C3^PIXy2m@hWh^6%l8 zOf~%645Ld#CbR=}U8K;_~*FUw*mEH9Do= z&01y|6<1G0Hx3l@p?#$-*0??7r?GA@sk$$9Km&1e5~+hnAU6)~>v-bMCQ<2xWW z!g2P;OG}_Gy{(Vjh-$a6so=3Q>uPe##`0#DlvzuHRJe&8KJrvdu5q7 z+#O_RXK?%7I+}F3N~2t4_%6p!9H}n(TT!t|$3`C@11LStuqH2ZHMUna*`ELaer36J z79uReiilRbaKYaK__y9Fq}ZO^oBoXKHsE?JkC{Euhsj0 zsA#sbI=MCmHFOZ)}VTW%yXW_h^r45HLuBVjD9~( z`nCtGlPh8o$K<1ta6%6Ts0tqGktz*htOT8@m(U3I)BgFUchHBX6RBGkcEcaZ1^`w6 z?WUdk%*AJdn?fU}Wu#W%2|;K0mRZ(VWObYVtLTTkuc+*Y1A~luwN0qVAJ4mjG1j7i zgiJ21;6z6-zAQnX^wyWnV$na>qgS4d<*rV^#_M*2Kk9S+3SgPUY)`tB#Na%!7nH_t z%B5}dZj*z2%|9VHjij8tmWoy6Pehfowmc3FNHK{wew4WSmb@J+Qw=!IQo!vy_BPRN zuBzTl{L$cZ&H(u0IDpO88L9KkG7j{Z=aCjw?H5saXZ1vt2X zfAMW!u|BNgbcuz8k3S9R&x(I4IT6aomXBYh^i?RBbEEvxt1TQexx+8Q<{QW?aBOp2 zgf{(-EpS$=b^d8bC?i0?+FB)0;%tncMaIhaLL|D}!CSwHcCvw{u6UQF%W4&5{1mub ziTzw5ol}LaB*I1toRK@LoSfP^qRDi2`2eB(4@;?9In7)aA0qZB7 zna6!>HzeESh{$;(I_(&GNNq)!I$uSXPo8#rccTwSTp}$2IkDYFEZzk53wiy%&vh*L zDKLB62(>kp#t)wK8^U-QP0V%^PElB;VJ~*g!e>Jl)9%mia2^PzT?cC8%7%CqBX{<}-8NK<3%wFKqh4<{ep|L;M}0hUc*F7hUGQ`UvfIF~eR3keW!t zL~vCl@PUt^N4BQF-&dkY>KD9!RMa69)EA6E@MwfbO#yUmVZfJdGSe4MH+UR7~e4csXpLYywKS11gWwCgrleY3rwP( z7*HxgCW1LVEB*h2XTbjlo=smIA>;b~foEOl;176q`WK!NvO%@L|BcTKK}Y`wpZ|ep zFVGy)Ah_Z~gE4SP6}lb{nWp zplt1p`3)Y>SZy?|Ze@OEzTusnrb|dCy{(;xwT-p6jhT#(@ropCNytqtCrGJ}4iSWb zH|q)1D&G(79KC~;2C-=b64C#}Di^B0* zpiJ^EvbIF(V5o!L!uXx~%_!sei>eF&LoeP8e!m`oV`3sGW0UX5hzHhv5KSk=O|plL z;+anyKnb<4uLscJh$LKgjmEo|<=u^P` zAdX7haT{oOOQglxr^~KWc=Bb}o~w|r8*8RjX{fUb^=nB0FfGK6o{Qy!;_Jr9|s%NT{zG$}{!Qh;!){`~L=6~~DSU4<&EFY*jmRf~yi-3M9dl+$YZeoEe;tMxo{tJ}!V?7KwB@({d-q>i%qCzt6jAqL;x zEPex<$V8EI+tI;N?l5tta)kg@y97GqLvME)w{EO8Pj;<$Ji2eoi^H;*QYZv!P1$JS z`on$`TgTK(FUpt=&FAet8XXg(;cDVhJbBW8x!H3~+$og) zJiHTRr{2+6Vw`zb>Auf__r$cwG}e%*wkhZ8WX>WA-VtddWdD&wD^mc3@TS?5Vv{SN z3_;6%yngycP!q8P-y!DcXH1;uN9ZGg0r8{wJzR%F+8TV#6Qi({@AKIYE&xjkzw_N!pa1~piKJWdS<$6rh2+gpSnKR$$*xiiK*oehrN@Zs^lEX zz!G0n!|&sgUsFQ()P-+|pzkG#F zpoW!N{z|Qo2nLlXHz_By?y>%WXuqJ7lBy#<4~v6cUt)PL!(iC+Xlwg1cryx z!bAI2PHLO%x_zX6#twApqjBmoga2U4gVTN-gEN!nrll}w*)-y1$iUx+SeB2Pa2(6{ zYJ>iH)jGn@L{N~h#i-$^VUTP`S(cBI@URuUJzz&#_En8<2#70_zd~sBP9;LNjL3^P zq`&I&>_cOU%yTVEqrYnK9Kz_SGb;5=IW^dAHT*1Mc-U%a9>FzO%W(B+Jum2Q8__y= zL4Vcq*iG}^n+NQT@V-7KL1OMqr9MVIR?@s%2se8!p&EOnneJS zfO!NE71w?b2$nt$2Aa#gXeg5r;`Kf>(q*|6`#L#i8_T-2}+Sn-4sJ(cp&<0+(tWx3dKX48yl zyL4suQb?vZ^d_UrYme??Wi%`&Q();)Q|$-Ft44^sWJ0Em9hdSY9+6t6UsJ=^#It2Y zUSzqXLTXO1{?q*vw^EvII@W$|1z(eP^T@K52p^uLrrBqxo?4X*-?$xsKjd1o6KNX$ zss0oMemyzU3&!q_n4rOFCsEk$qm}lmynFjHO11YV((Ti#*0lVU+zFJ^R?Krj1W0f@ zrE2z%t0z*aMwLtXW|B|ky;L~)h`V34EXSZ$tolS7#*zgbnnlS@c*U9wl`nfja zbM#){BZ&Anx1l4pCaw`=b7`hn_gApG7^hhF+sSXP`QSGb4t1};Ub(6oj2gOYU50jr zZ(;Q4+l|TYmAtl1Ca39M!+BA-?$Y|N^;Op#Xe?c>HK%sP8taenZzU|bcH%Yc$6Qka zs{h#ce`{Z3JrTeQByX8(cPu2fj;%di@iSJkP^<)gj9+A3E5HjRd1PEWz=PsDabA%d z_K^1-QbUQZmVD@+OucF;E|PrYym~?s)q=G;(uk0?>Qn@*#>3=rTbNbdbiU@AJuu_3nK3+sql(w04slMXxq^h9tz{^Y;zxBjR7?NV%s1-l zmE@#pM57j1cFkE(Qyek}3jpHx7OkwKPL&9%85y*5YT7GDWawXblf_B%8|2L`fB9$p z>Iw08=Eb$<=vCt>{buz`52CZ9d11+5<_rLdBste|8NQe2t6IYA3D8acvaOLa?yN`1vliKQz;~htf4_B~E5a_-dbU$0Ix~P}| z@?S}wRsVT^Q2Je8s|EmrYMsn>b2;W@yytilEkPvEZJ7@HoPk({vG1uZ2eZGZuTS-b z=Ee`vym1@fs^6#eAhemCDFT1Nu%i}&W6d2k6EGlx?)NuCEojH|@vUw-Yj0a#o;r2Q zMY3MSqO`3|m6r~-aA1a*g^o0_uQ?qmu3D_)$)RBu`&GaB*#jg%K8MvW;nHu>(?AiE z+A*S+Cfa$0o~f>U!w#0_lcF&yPoa^CirlTPbrVTUrewAw>9A&N=+}w2-=L6c62OYL ze>D)JsaC%(yF(p9XZ0&VwfsJf&WKPNo3r_7C#tc^Rw%J|@D4M*956b{UPR&D5-l=r zJuG~T*TVPP4%mt0B|cWu{#8#35&5a#SK_4smo1yhxevY#h?f#uv%6C6*}-_TA>|l( zYDvqYjVnZLz?=9EqZj2^B6vhqkiE6~4aTdPk2HGPDp%zs1}k;Zot>-kvO(Q?o^q(K z^cVkh|7XH}+STT`oI8R1w=_I}Zfk}1^_$K;>TnqcG0@-3Jro|k{>xF5W(PwgZc(07 zHTFJc--UXN0&&;Y@s5+p3W?o;WDfnBB@7D-zu$q~X>L|4EWFr8u}N%=#*wYh+y=TG zOje($mn5Ab=Gn)F^VnjZtZ|{W`VTH$ig5X&-|}OQ6L= zeD^!~46x(q7^U^rF$ii*QfS#|O~7}4xmV#gIi9^2%BtmW@^jx_zvkxApRLRArRO14 zMJ&jU3iMY+MdbQSX>$AUb2;AtsyGrX|?FD>7gYg7Vg^|#%iF7$h80?<0#LO z7z!uR?yl!jb0^G(1zFzF?fZL>BN!$`>AhOOo=y{z%G;qYNpciI~~ zOScZ~Of_`bI?aYLMQ8oeI7;19`+_I)7N9+pym?lQYFW#)vbB9+M1#S?Ps^d}yyld1 zw6@97vP7}hBb(6zb|$onbo$%%Z2Wn}Zkq#y>;?&vF=tZ5lPrQ}S&aa0=2j$)1b3w( zn`}xAcPNKnO(PqQ{rJGGipjm_ZdSum^O_e^55(rP zuIVia4cAm}v@Q@G!MGR+S?h^*9p=Y}%9ZVM%E75;w^msh1Slm0#G~(zu>Lf&YPVl5 zlic0h?gl4`tF6Gqb@GaF--5lILchqxb3 z2L7jk{h~w=*~%Lpnwp^Wk5#sZlOlyg;Y3r^KTkwQ$q-R{u7c#>26ysnnD#vY^uR7S;q40+Kzb zlmu7??MUVmlpA9+EULqRQa`0r5x3E$LhNKT^@**HlzhnWs(PqmBmd`qShZE59E7+b z#uEA1)5bPpOvW(=114&-Co)5nYt<>%#%7A67S7hE^;R%pKvt4XvT5E$JYMZ85Q03% zuH=Gsp6+@K&n?c2=Agv{sH}ox;T`tkgR$F$_(i z;|TO!=$B-3HfZ|BG`=@Rlk19Q&OhODWNM7L#|*5|I+AIJ%;V}jv%++hbvVkF*fWZQJ|ic(fV4 zw~Dla9V61cL6QrsiuhOp!ooQ7+(9ZoHjHgIBs|D)M~}SH#D%GIxAR z?Kl=7R0;Yl%K4|!sBEP>ie121W>|a`Y$Di8`o@NwwJv@Dv1x^#Y#dZxQ0b)*R|+Mp zG(-;fE$r-GBNPxJyQQch@ZJZcpVdMrYIr5#lY(+&(B0@d7=)s;0_(_A^oA{O`44g9 z@YitrO@eu~rqrLDlTa0;IdV@S=d@!F@|n`#1O0wAM|tLxN4x!uy_Yad$yP?$R7BdV7gDY)#|o>atlBhWnp9T2rk94#^T2=oiGs`SnAO;g ziyvQ5dKf+jW%i5Absj;Npu{56CbfE8t-ac!l7}<5zcN+ay4vkKO?bt@>WLM{l*Y}F zHK#!^c9PPNR#PFz^2{QZRT+l(X-Q{uYh5>g?~1HFK%6XSKAU`;RGO;58(mt470*~^ zYciV6J{ML^t5zbfvt;}$q~({&NW7|otToNJO|%_SlG}xah+Oli#zMbirRjn*r^Aqa zsZKOA*M?DusG&P-aGg`p>$& z&8upFESjX$U6^HEHDm!9`TC;4Dt3hS|>J}cZ!dg01H_R(L z0k6W&d1Sjg(dI0Xjiy#{yE`(sxN85Zf6d}q+!=)hKb*=QV0N8g~Sbj?eI zxHl+9thi&HJWuGu%%HZUX((Ba&c;WLJUl#Fp4)9km8TLKdXkF_EZlsDGajic9`Z7te8MP3|tW+Mmj|#aox5?n;6D_^JCjsQP_0&g1cl>dsR4ErbYA z2iO*TTAn+f!>R?8h*nR??xyhXYQaLEJz}4iH9nN{(ocF?p4I$9nVWdQv3@*yUBDRs zNJ+zYRrRNi@9EoGO(xPU880&eIJY$NDw*u=C`gJyDu!7n#1&Sn&PXEG9f2Z@-7AL_ zB-xpv0&Ov-Hro`<%)Ok`C}NtTq?1zMa%#W2e=946vPOg9NK68xb^8Y7PUI+w4+Gf1NP^ilVj&z5yv8DlS9 z9cDNEPE+VyY(L2y%Nmo>!V)Eys$BXW&pJJ8D;@3cC8KcPfiSoMSeB{%B0Lpbw~w`- zDqOe=3nGF3j#9=kmyo;*1M(=dv+E(TiX{I#GeX1A*q`a>_% z_&xC44nOQiR7P9!E`@2m^1!qWs?2N%XHWNr?6?3atdxGqHX}-sJYtvs}YdA{ff z+CT@G+c?Ld`JhQ4pp`aD$Bj~%32xAkCfW%$KlE+W<=P&?5mLmUmD6nLM^s97LCSpNlcwD7-o)+chkUtm|$q+|r(8Bt|~CEJGkt0!AL_S7|3lvy#%Tf+^Br2JeY6M53r z0bjf3njvB-3Yjzkxq64$JytsLJoMuW{!{dL|4e652jFLka$2k7=~q zwKIY8;~8Q9(;Rby05z2~bqtC$$2-KsULFn^j)jv=@RUmCZx?^5CwXy2!GL9Houh7lk_U@q2Xw(nuzUov5~ot{(Okf{E|oa@ zZ`r*WrwuDBK77l93lkiG7jhAEx>$3)1Zy9OQ{ycXRcoraKge-on&Vj+F@_*t_ zg7AA~s)5b3UVslLr-ejMIk2$bqz)4Q1bD#6R({tZ)2%i|=8*>V4a_Tbxdzvj6H^Rg zsJVV&O+}Ow49+wo_HjQVuxrhd2H#DdXE}_$6pL0i5bh_5JbE%+I5H=glBLw8BOs}{ z1vof;*8JrEiB~0V4ly6^R~2-tB`84okx16Q{y{7bh6%DeAd_qM45N z?L>X^T>K*6QQEDDNx2w){^nyaI9%&Z14;s6A4)BXbsDCp?*heRJc@c|+C?N*bG7w# zTYdfQheQMxzCoLb+fH}(9j1d>_%f*vHaAsd`g(-yr@D~uOeYH%Sk5f%1R89@2-Mf= zzj!ZH8s3H%y9(756L&KVjVc&NYLV5j1WKFo2$TwR({UZ2J5#Qg&q{KV9z%Pt0Gjx# zB;q?XpbdMy0_2Gg!)1SYudk#oAGD#%P)jx=yus_ao@Ap~NT_9)_zjM;G-PHFtJs`3 z|HvGqy4hPM^_$6|>y54wBX?DZnB#7z!LXyE2-?lilUhLdqjKGI7(w=z`;`V&jzr?L z;`Eu^vL>SvNSg;GCSLu-(#YS%fQo&5eR_q8ELiBqW=l6mLqz%`uUK~%87F>5jJoFX z@XluS#7!``7!<=ic_vtw-yzwC-O+IkO-;@Q+cZaSSlKY~w@6Io|GLE!sa3-yWNA#0 zn>e2~I#W4^Xkv72z)3*H$H7w$tSsCt>=F306Om3o4C9{StgG0NQ3R`7SSW zmOdWnEJZYq`uvXX>JOusRR}h^zhi@AYKl;3VjOn#s|3bY6UK1x+Cd9sSCtMfq_k9e zk!wn`4<51^34R@axcL%zB9=}=$!ncWE(zVdJ6ZfK#x$RIO_z^c1``95FQ2*VG2l-# zS9ZBGqRs#QgX_;PE|C~21VZduRSDM5FqyZ1$ZriE;l(A(yrccgu?+hf;>sslP za5r3WmZM_R1P!8i;B#hQcmnr_?!Lo1vF&p(%3Am8Xu{hJBtKFJC1B8N){4;sb;qFF z0U@mlxmq<&{PGwIGHi;=K~s2Owp18|rnmnL&`y&-Mw1=L3qd`JGnuvqx&HadS3oPyMwljpoD;d($i0c|LpBi%JFI=Cx1>M^&5m16cl()} zA0eqaXtKi#_BUbQ058*|qHJd!*UYbwLc`_DR@&SwoG;qQ z*EN2q20uv;6(KW^`*iOv=!U61EXg1rpCysR-?AGs{YIt4XPvFdXQ$k=M?|&fYnENq zq}SHz@i#ud22S?xPR9zWYJVBDwKXUh=2^pDJ|~hgRxgr>m)w+WK56Y98FhPP)l|7W zwkMxQgV1pz&pFMp)HF0S)aCW8ziCp`EImECYn{m@D1K0?>t}iBo{H4qmKml!bqPZy z`#z-I6Nleq#!`wy<%_K~%lMaI2@rVaIYr0};>{oE8)R>}_wFOY24QoDLH7M>rjQDjR<-&7=FoD8m@V zI#l?p@DQ_Qw`s8GBe7=^!{hO;Xuu&mEI@Q>fc zdEZg^R{wj+9ViBE?`@X2|FORQbh73-4)reXXa9ZmwHs5V+t(OzEkl$?15{Y02-l%- z7tWsbeZuudHyozm$08fqh-l6-Z_tf}Kqxy~N=BT1%3><$yL(Yb9@mkb;ZshO6eyXS z9O!Y`EHiHQL0DXzSC6kgeV>yaV~Q>V-h6Khj1#Ti1?TcJ;;r^6JnDX zllipJe2V?MwtDZS>iCWnj$X0T{+Se{0$d#Ngt=K2cH@BgRZ-o$B0p8EDuM9ej*b=) zAlK{My=B1hv=3yp9J!g)xegco@*Gwk#%51%U^GiDm9gELJXHe~(`361FD#=QMo&39 z!pdr7MoK9*uN1LIe)zXk9U^~0**euwQ=_k{+zo+m{kGlbcoq2XgHEN^`Q8&>1W=Uf z7C(Bm8QiYWB{_ThkcdrgJo+=Eex9v$gif|qMb)ot4e_&kG_g@nT-oV~ORF}r`u1RW zWZ=2%beX~{=npK}_yG3hb0bpZZLPY)l27L^qaB@J%y5g}IW~><&;n@7=XC=%^L@e% zG1Z)ZZo6?J$sImO>*FkZlW>Fho(E8P*v2k!jGW}L%ey4Uq3v6IZLxW8SUp)aE$ks( zYDE1ghr~Q0+C8ZrBVk)vcGR(|UD_?fN-WdZ%y-qvh4G|UJkm;|{#W5aTeG|KJB8&6 zH&NC|*g$)+__jsC%7g^b@}r5Q3q=thJHRz}hKCvz|FDU#i9_n>2m%=2DxSr?p7x`< zud2S}rC0-t+jm4vXh57BlhmRSj*{`47F>H^nhD0KVvE*V`CgKoIL?0o zc)9ZYc9t%lNV)I#vz^n$VHl8#wpzPl_{bu&8% zMoYFyCSA~PWYd9&pamy>D(W-!$?AVe()(h=B)2?QeSy65Oxs#JBnbSy&w&qoFIp5A zizoXRci-~k*nk=M3x;SMJ_lFZO9ytlrtZlh-2B)|tfwW}SvT2V$c#~Sf^>!|ay-Lr zR0;+59Mi{IcY5iqsk1oe;gBNfDZdUK5*3wO;NICwzAWxjxb7k(2%d4-$UW`l3BDogxv%&jz`$ zM;4|lP3T7$D@!5S`xoHo>kE~%ACw>CCj1=C`YkhlJF-Rab~!k6V<|U6qfJFql^o`* zk5`1GTmKobn&`)D8Jb|Zju6x~VUX^FZFU}1D7|?e~;`x^h zM|2mnug3`PRo9ez33n|;#eXeEkQ4!WK&}fKkbCqo`nDPM@Us|1(FT1%t(H3jJCbVd zEvIOK6H7O7ZN}nO#b--I&p2^!CJ62YQB*p4zx+~wH8#soU}Dpaof^9B$q0Nyx(GDC z%TWR}7pF{pM!zyXm|=TAhZqlmY2k*d`|zz8YZ0jaG#4WdP=tM$8r$;)YrmvG2&x@@ zCJc6F|6LKzj0~w(6kJkng!!!wi7g*Y-fGB>8`GW}{-sZRnW$zE%!%&6#(fNn!EAo)iV_ za_bMjR%aVq8CY5wWD#Ctk1(g*$c4>iOdj)*F_BG~X;^x(@@r4pRC)@|vxzP-qYu=% zQ|(lsuk6%0orjGw)*~MVjRjF>fpJL-;Yk)1N%wE{JMGdkrF zYX3BTC>CMa0zm>ZWfR}Z-W0gk+eHNJ2Za+isvmX5F>{0Az*u$c7v$Jr7Vb#E*FXS2 zBup5S5J}bvzpC$wJO`aP0Fs;secOeed_+fVR^zLW6B=Kj>R;__IHqlOPw=t)^=SYif&ee5c4)59~T0<*+|2u253yYO26*h#~R~#WddoQ2m^N6v$@lM|(5xVr5uZWJu#YE8o>S?<@NR$g zFM`FqgPmfp$a?HlST*xOxU;+tZU%kWPT?c z;$X&Fnk`yLQ^gre#3f&`KXZgj=~Zs*wW%D#%emA z-~4%BOWg!W7We^YA}=r>yZuH#lQS70^Fe0HFMGCHCOd%q>-^wUBy!>`4FizJE0B3` zUW{fK@97s|*e>E8FidP5K)d9y)F5p!_d7J}Hz%HjcoqQUlCXZ%3Oq^Is!_SL^gufev$Q3nhszTmqR9x_H|X+$D3D*Q3l2B z(8fFs!%dD{-ZOXJpEMdxYMw3Jpj~7dFC)k>xd~fv2bZHbm=6M=aUp`RESoK`iL1y+hVWv z$7feu*JhzM)Oj0S=m(oZ%I3kLbKPCj{-$^up z-r8*|RkMu#!s*P?GzL4(B}OVedK*_CWDnhmDq?|a(nxn*6V&Zf?*|CP@JQOm!y`NYqiRVvX-?!m+I9VrGlr z_QCJDlMTVcD|uuY-XqL-iMDhbd8a~C9E<1@u5dF&th*)>y|8?Nt7>ioc** zyq*Kfkz0gUWVbE4w@Wkgm^DI(K~aNWBC|1Qrf5jRE}7ZSWrYZWzm2+_x8O)wWbG2~ z1dnnI5v#D~_c~1;#$WNU2nbLJvuN${*r6Sw->_924Tf!pWd~f;II9F`m82uO5A59^ohu9b5w0P}!GHD3 zN6-BW!tQ8EdwwVP+M-Ijd!u>aPkj+6N$~lO>oVn3bftf3=NF73NCsCIAIZ#jh*AWg z=K@{JrZ!=HL`+gz&8Me|J5|pzDkQx=)OjB)75m+0ITt}LX#G5GX%MGi4JXJ6N(mml z3UKAp$z$IH50U$2^)Frc*L)k$YNxlDjxN+2o_H*bBTNC>@7vAH zudEg;VRhC6htxPexgs^#G&w-5+7*R-wFtDg8f;nQz~Hvd=b_#t``%l1$Wui_+EX4y zvduF`in-n42cJRhQsla0nrn7_j-Mc zs^Mn>z2k4pbN8jKO6OMaHt;*#;XM`9vjE#uNpm0`&`R(vc>BT3{sTp~{%DH$k_*ER zBn|OcO~|(ehDYF=nNAJo2FI_35n&R00270T9m58LNVzEXDI~2r4)j<)eYYlh%@BB> zg$1e^wnKjQh_fzu$lm|RdLtUOdP|5t=5>OAv}QR`j3#APmP0EE2ELR;nlwll;UHkB z!qAkytFinR7Vi>L2no8p63=eKwHu_NV)FXBxdN*(2IgsrjbH*HO}tsu^Po=k>PPe% zbXgiMKQZ>A%$lIws68NP#CB<{eZa^((Xhv#o&1p$)Bt#~YR|gYm0#^H5ZGI$4RI$cN=;`MNQQQBaRGrL&U6`@gOr?>*0n2 z$P*d0DKM}v1|FV|I|H~7`E9T50`)jxw@L&qZ_yJER?WdXapcRy- z68es7H!x)k?PnlT@L`V;eNI^h2oeTUN%fIs>3%*SfixUJJKL2xSf>=JYLuGk|?V_pd#(I6+n(r#lY zuUWuan!^}Cj&{RK!qeIg5BT4a~JlfbhzV)#|HhM~&G>O6dqt@uymRD!%26#`|mPd9b=Z^(n9N z0!IC4p|b8Qzco!PB?B+Db%91PTDo$o@)^qyi01w~5op7Ifhl)GIaX*^lk2eU`sv~t z@N5HCZYG>*s~t^5X{*L(TM^)G?2>6nd$ZZh2ktw>j09D(H*G(haKe7B!mU8O}$JI#6QA>d9-h7S+F$Xt!lA$`{*cpDX+=bM*H(Xc)x{SMt`qb5KE?P(95Vx4&Np-xeeMKgzEkZe8)eC zj8QA47MjA!3f|H$CM;AHcj(F3%F7P`xWPTr83Nf-yWU7}exn;`BW_vlI}p{4k*1hQK`LPgH#lBa9wQ<^n%bWI zX~_Ooz=CLPz7bp50#PhA$-jGbSW?~p#D!uR)1S$ z>2pi2O@u^!y0GfQf-$+1ZJSACP5LCJYJVGN^y&92h#GDcGPWGLScKh(oVHw9%NeDv zoA485z6yhJzoTk+Q}Bp?x!>fP*yX#mGV!iPJefEMN}oT``MJRyTS>MFtN8Oomp~e z8T(uZOFUEB5F9Zy|90=lbSdhEJVei?{$N0@NJUVL>=v~dk}Uu z+SQnbK819=M2d@7T|e#ha*|-nCbl1iB~l+-Jry_jrpRm;WI9jYya;!pc6or$TXxs+)*6l49-&1!r8`11d9rw00m^8dpo zefs4xp+jJ&Del9-2q^#J{FYQYy*w&8SF$e&{5AIgZ>8^SqrXjft)?8tnS;K>^u^xQ zV>gjY`j(XAda$0;?!n4t*aHYaDh*1cIzffHYhWBFJQllYI7Fjhd6lV#=!T_iZKCGbQ*_(?m;3Y`J)|}y52lB+;t)P# zd0Sjpq}vg~1gp45+uDq6E(>cXZ@+t0!-Wqh5}LJ&c)K825-oC+%}xdSRvP+ti(q=K z$RI9U*B1p?1~EQ^OMX-eRrluq>!>+*?RSnwm9Ls;xZQFTDb!unJ_+BkMSWYy0>(pq+9zL#%PP>rB zp_3fcZI*ejT=Hf%M!`dTOcLrv9>J9O9E#!<@CFN<-OBEOTWn4+-J)(gy)pFHQnJdh zvZla|9jOgV(W>H7;bx6PjO|Swd4!Y3Vql^6p=s1hWEUVV6Z=OqB!^Ed2MMqD+NKYZ z&?|WlFV>`^DzNdRm+S(wDjD3oXycwg4t!}^UbR*LT$M(aW38a)oR1J{s;%MgK{ z8x5K(*WD4W56dGQM@Np5ycSpU z<&E=q*DIM~uqSlWoWMAdF>>~4YnMJ$$-D zG@mPI)z^dz$LoCt(Cb*>w<}B8SMk>c44^Sz;T70GbByw!ze2uJbh!KsQ5Cx!BY+6t zFaminOz(wA)z_>~rPN>OHI0cVYX@CoPZi{w$|Qho$Q;b%^%(RcLC8~jFB1Fln)YWx zfAZ|tS~d1Ac9`hNv7s_KYn?iSgV`^vpC36pO3^iCDCU~Mdcr^Tj0yU3Dv-}E4V;17 z5WqSZ6Lw)XjC^DbW)gj3jb_UA<Ll~DXg!koNU6Qt%SuH2A^ zoLBTGjYj)V_jg)GX}0;;%C*)fjpq8u3M?hw{D-3r2&(61Ghy!y`12$l>P=vdpdRmw zfab6EJwe&MY2xG<4FZasqeF5(DPC{zLWuWWWNYH-n&2uQS%%dRVr1EH%T#FDx@{0ux9TKw`R%q9NM;fE? ze8@PLta}mW;;lfUtGIZY0WAE#BT_YI#0&Ad^qv~)f7G^Y#_h3Q)f}dh%EmrlE0ki2 z{Hka|*O%n#C4+Aw(Q?97&Z`EpcI*?e;!E`M0zo>C!P9#cc+MpAK8}cgVronWR6~ks zTGuLGxQ2{e`E?G@poB+sk)lOT*ooIwvCvlYs&VyWUj31 zRK6#MCwutKq}B%d4U4h0eUC>M=(L6ZFtm5N3)cM&EML+KmVL%gC~eF9a%&>#Vf>MTZQS)qI-!|3|5jRJ6JFPc*C~2WwDA2*a!>yeY1JxZDO>)Q_3}B8zNgIaH$||3dRe3FEzF!n4_vK9KiTvw0r+Saxf}kd1-87Q}6!gw81(-8KrbylzQJ!{)Eg&I9vgyt6Z zlYSdS<}R;cmd_|--^4IVP^G=b^v0sYOSkJB_2kIW*0H)OhOB21lD*oSvmlLaj_6X- zf^0MqmJUTtzAglXpe|g(@yJT|5T4{*IPBe214E?GOAhzypK2a>I;IrXb zq_0Z{y4%Pv($t4gU;Dx}C&>C?Vh&nl9J}fo3W}OjLei>b8aZi@IGYQM@KlWed+DhP z^P(NGM0zTQSB9zrYZxo56-k`5g#Z}vBn&c27rGvU5-AlJejTorN$yq6)QJM}H1=pF zjLVikwuqdLlym4;pD0@LCyG|JTbdGq#3H?rYxS90+SCY~m`8F2Pwfy05M^G=yt|mR zoBdrb>CoHSJcCP@BwRlCiJ}4jv1kK!f6@Pc7R^9XNhh6HYS>Nc*U;7`VdHa5g`Z_< zj@@YMPkd)9pAy1)7isF{fAHchQ}j9dIpk$gOZKEhvazFTqBMtv`CDoOa{C3iXpMS> zlXTh`2=?Jm=);lL27c7K7icSZ_e0dF7e73Nkz_;D2T>{QD|vx08Bh}(RcQHQ+UjTUtc)X5@A`I={=fF#G9aq1i~A--7(lutq#G&e zQc}9ROS%O_5JtMBW9UwiRzN~RQUyf1Whe=0Y4ANWj`w|Wzt8je`EvP%<=+3b_S$Q2 z4rey}&PnEX-Nvw{<>3EAqA|!jRrkyNA<-6^)Aqi;xvJW!c^QFmwz-tNpWzTvj#GFv zp-pdJ=9cBiT(oXT&1Yp1|5|#yg82=T3`@v?>ps{X%Uz$~l?qX>PVd_+2hcjJKXnia zcHP?bui5q6h9qZ#POtF5cItPnZ_jRNI`w=teYc47j8E{Q%R-Om{>l1ztgcoJUBiZa z#29m1?FiEPg>(^atfy^V5S4S}1W{DwiNI){Rehk!=B~4=>--K|aqgY2cj;eTg6t?Q zY76dZPTv{CEdD&G=qGI?Pe2he2IE@obgs=8e zc$hRw1~9(OPLV)ctZhzXl%c50FsFeQ(@LkqNVLy$v><>)D?d|00Z24fstmJefJAFi zd+<3KMxyy4NVH#?ijn0}_)6zsrYy6Ea%MU+?IdAG3Rbs^$$2NqhJOPnT5O)jtO<-n z6JMEy;(CV&bLa87nAH7~L@RCe0Z6o@Ab><;<_+|OlW2YaCDAC{4CP=Xn!*u4qD^dz zWgd`eiAf)-#_r+k{tB!Sx8+_^2cK5F1W+^^m6*%Q$Ui6=fiyUkRf4DIF+ifpH(Wlb zhmmNkFcM7{Akmg#B-#@=iRMQz(JS(}?xI>rE>2LGwOHS&19W_wF2yqN%prhM4|A(Vn`c zn`-(2B$|au_Z>DXLc`Wu7Av%CANx5Jhmln-Y9>OPBdS%nSc+e#KCB7NLyLS92`AAy zLE004NVGx~)y?`c213pa7>TxWX7vy+>cKFt;8zlFqf8_Joza&y?UjWo^o9=L_hQPg zeIzjxRU5uNySqtzb`;ax*Glx%C{jl^#NhYn0h7v9J1rjenPHk4$lnR)c7~`FZGp~e zkn@K%oO_}lR`e?&A}v}$NtI4Eca<6<_|gv_IPiH%%<|*7I<^g36Z6{I%`aci#Xq~K zi;umE8+bcGJSQbBWFh-StFO*92^>MN?@WIoEQ~dfQ}MXk9Y&({lkV6R4?TVo*k&5E z?|`A?CCFQ?m$vDqMP>1tr-Xxl^?6CFY`b{#sJ4~L^G4QZ=`awD!09UtL?eNLXheTN zv~dwveZR@=y!aUUdgTY>_A+UUx8uzde6qjKE;tJpkMuD}nt{bqzUqRfd)3`4G9A)f z%t8t;pl_g4^~_{RB9<9Bl#k;CS3eWgclWRP^q);vu5Y|4M*lU}$RUPhR#6?39I>`J z+=`uYi!h%C^t@4C)>8(Lz9P8X$%PS$qpTWy+NRE5jb191HcgSO*!(QVAoW8z>j$e( zdF8QuI-tya^&0Sfg^6#T11l&51y-k7V+8h!!K2a3H47VA9I^v8z;jHoxs^ar!4x*g z!IG})Y%|I3RC1o%wswJ=!mzQm)NsL=*Se2|Z;h5+fs1S-T10IUK8bDO=ap9<*2R(% ztVE^tU%8=gy=QyqP0-b#y!_sjJ9E_z=e%p0Ys%KJMgBHev1^KK8-xGC;i^?vsA*R8 zZKRkZ#c;<1XMV|)nb*oGnXkKa33ZBNXt6UL5-XW1SQ|1vLF}WN)VaCHUd2luHi%XW zenj;c(?EkBA-{L<4HTKteK5vT^14pvU50&yfkQ*gtj~BIN5wl;W;CAh+J=n6wHb#T zq50nEJxhYu;9JqD=v`Dle|F*(vlw#C>-k|x<W)}uuroA50?ZaxXR8^05nhP>g z(TU?0omCG-HS@>@IJD5oW~UVefi#EO%G5Gf?g2;!`1OeH=P?hh%I_D7S}||O*~YCa z#vNiRRkfMZH?55-bxPA5A}U*7&*^SyKX9)resq==x~1~2Q9NgLk6k9IebP+l_lDX#K>7^*6E!|b}uPGNc(p)XRk1k zQEl7lO|Vnv=c@*h$Jve*uCEW3y*^ZO;+1APG*xnHi}u%Ax3{{m6Yv_De1RyPdXzVR z(WZCudfyym-H5BS_$7v2#Vf6{N>eX$libLpqN=`D$;9k;hM{8a6$*6rk#*_;jLTI3mLF`Cccc{^@$DsD7ixl=pN zne*cr@l~sye=f@W8?&gXO^IKqM)TG8YGhl4QY`bG+)97MMApyh;=UFaFb#vuZqoj$ zDZf{%qwSU9z@=rGTX|2%q~Sc@_ls`aat~4O^d^Ysv+l*&0fSjUH>C9Rz>4Ry_D82* zZ$%!_f&mImV>kn#&;q&+{Zz%{xLIN<>c_E+btc0300`}s6;I)*792t=HL@z^7Mext z^WlzllUbvLL1>>?m_R?a`}>WbJ@anxRp2KrTUVF{>*fIv+U5I7Qw;z@3rHBzWzxkq z2s0}jqfLTAXi@-#ri7&4u04xa0zUHhiWxuj`a_|i0~FejL;h#&cId`+M)98Do7{H( zaSDNjsK)e7fO2c289hPQv066qX{@|1TX;Ke^x}-r?E1~MWkvhJs_W)%iEp3oZ|&Wg zP4QnJDzA&LP4Xnj%*$}G#=uU$63(m3B^t(=H?>0Y=kIb?e;js=#RJQY`wrZ1Bzhdw zvvn1i3hgG>;R&r{u+J?YcK(G1Kxo?NDyZ_Z^|2m!Z1u!M9zQB2xIjzE97mnbS?bYV z)-!jkFGHN=rSaYGpj!Bn)IbY&r`;DP=0QEY;eYJdNOJJDJ339jS~&PNZQ_M-ZtWY7f=VB0dQcT){ckh8U@mV;UhWHKMVfa!QOZ^k&e;56 z32XO!ua#N{GyR*_p|SFodbp09tFvEh;_R^-WAJ+|l4FjMQ&GX;th4ww-1HC5<4y~b zonL7pe>1jvYfogmqpNm=b=Fqd;4buDgnScYmQ0#9if2Ng_wKUuvV1T>L!y)3S7j@d zI1>koCvw8U6*V!Da>dTdyiA!6*brsf3Km6WE4I7jv6-)bhwHFpn5D9-mGBG-#PXIT z36MXY?ZsXu8!f8?$2im(^(z0e0bb6*#msYF&+Ab)nL@K8AzG;UOCJU5(l^sfX;oF; zJKZa$VMW2;`(jq#d@Q5aU92#)M5FIynKf4p&pKbQHG#6(IV%qbuQo;&yIkV4K6t^q zAzr!}P1X35WYUN^hmD;Q9$Q_gfFRL9VqKg(s-~WO(;{~&n0HPNQ>8vo^x;%KYLvzN zOOaJ_D6b`tq;bv&zYw0IQSg63G)xb-Tds^!8h=1Eovc?+h%4YA8vU4l%9~Et{BUp+rkDJ%Qy|4kfh{0;)V^$2B2bF5U!hpfb94V2Z6* zYdKJ8Ree!Nny=4%c$mw8z#;a*fiv!&_G@P7gNX-k?-(33xzoRo$`P9Ya5%Y-!+Qcx zSVL9EzG-1*d)#raXB*~4*T=KlU^T?@tdc?=xitUYFTcO`$jxzI?wsD{ZGr)Zx4>Tf zi6bMs%Ukz}Zx*+l=HP9L(Y$k%6j1taesEsKo`EedebD1Pf$WwmIq zqHtc8vI=)Lwl>b9^Htyk%W%~@m$@=b3P=P~Iqx;p-kR-Yq{KJ20~<$iHv=r%3UVZz zMT>p_uxOz@_a!j}Q9CiB#a-2wZuK?2n(NS;gT!#(kIp$f8W!1nILVrCx5AFo{~26J z@W2&Az?;u?%;;AVlSH#0s_jp@c z?_X^RvvPgHD+vfC)navWJsR1?S9ng-<4Q~CmUv2hqD*jv(^16KTB%b_mspmpEPrTO z_>#g0wew~B^z7#La|+``Z`aG3g`tl^qRy7XgrnOMY5^28;AM`%sfD4kA0JuwyC*SE z8+yUXP0U=pUdyDZM*a(fLq-qSDUGQO^3BQ&dRKdiNm^}gZXst=HL z`az1%@YLS6gA2s&D2h_sSZReLtRT@1uxOVD7#0=^auIjS){v|@CV8&#Hb(=ur}LlH z%;PZMQP$M#180eL5k8QUWn{fzff~i@)I+>lS+bof-9mgmRKFjmIC$4&Tg&E4`tj|0 zeb}+4tjOJCS<1Ep(eQXh-NUpiLaMCpNB12K>t2?mg(z)jO=j`+zuCxtwedAN_cq0Z z5%AukHy5AK3w)TuOI64mgYyUb(60g+JIyQVjdGhdFUi1q-##CQtw@af(qGYfjF>CC z%miin7`9F|<_s%^YQ?Im48OI`&)-6e_T9Y=u74W!>aBQVRlfW5Tv!HLYb`&h|KQP7 z%ff$Hv^V7$*Th(#@2|>t=MVUcjTET$hPGXDp00fG{<&pe9k6ebICSrQRO0pmTdygJ zO$3-fk(@q_FLl`}qfXQ-Y2I-tSz5<;QjX*55!XeOv}lpOSPyz@OvO>a*>5aY^9L?L z5mcRuGz|;yW(IKbYnT@>>SCn3%NfJBGrd1y2zP!B(hWe1+-chlH+SCCcc8vXxK0s%}O|3*&0rxy)Bj->_T&D zeDHJrKQJ15T(ZKoW^B&-IKQP+6&v)<0MuE>WmeK$k&2iP`8%@Opj79_A z(0--CD1IDTlGAD3nB02%7r#+6k%AT@0HbkVoO<~`bj+P%$@&>E6qJUmPk`yN55Q<; zuUr_4rRTD(r)&~Sk`8&W{hJ&m%~5}SvDqtH`z&yf?`Nj8);a14B`bE#Vi>}Xq*gGh zG7IAZPdABgyE2&_Zce&3oqK5R{+3d@A4zOQ(RfZjcxeg1Xte;0)?4{SAAr%A02qzm z>xDVz7<6(vc%;T>qb}6b)wnfl*I_lN_lc(wx8C9!m+AB)|5UD#bxYR%ajc~BrJ{N? z@kwg47OF%|Dx=XSqV*#bE?+OMbsjBhl2U+|16^?jvP}6O9<$%tEoXM0R;_Zw0nm}5 z{i+ha*9?O@^MviGR~_XWdRCA9{3^^UOmmX#srptjvjp^_1yz+2SIzL-inRLLI)5G_ zA3H%y=Jb!3I3{hkiTv(KFo;W+t2gx2%`~qb(&{T7=Lcg(5 zX?}SYz$e@|9*ZOJym9lBVR)|6)X)#Bz=ZDElDWjQ!}ZAtRecNc$s!nx_EO(cEkO;O z`nq<$g}>&dWAA2Pv4m?{=Su12r*g2tLX(rbc-JdgvpY17S&hYvB=|n{S6@EsQO3~o zQiW|))oPTM+K^4>qDt@%+DGuM({FN2Ss2e&KIg#RC@1qe|4y8Vx!1g(u%wXU3~cC3^qsaWghpXuH1@YtpOjOZu*ULZ$p%byAK#={c9_u zy&O|gu8?qLWq=9vrPo8(spl!H&xRP!c%kvvw|sNM#;bVe)ED)o8>%iK$=`CRhp+k0 z%cMWj9VTzmFY_@*9)uBQrE4WN=$LiqLDd6I9jwChDU8ExOj&l%@PUVCpZENb=6YQD zqrvOYX40rZ$N;CH+->YUa&jr1m3Ce26*hw=XmHNuK z#5G-%29KR@Va;L7Q0kPe>4<2HU_Yu(J#?$Bdj@ei%>67LSeva=6mI+mYH z^|i>jKkLwPrzaI`9*h3TfWPprmAMa04z{JgE&vPjyT>o2rn+Q~Sw8RG%t6PE7*&Yo zN2`s=xNJjWhThE*QFiLH*_>gl&t7iy@_eQztOe1gI@T-Q7Kn?K35X7GyC`PymoL7})&7OPeG+rw$I1n1^?A1bCvJ&dzno9hl0a@DE<-pDU;w;=V5r-ZE|2zrQ@&Af%P$5sjl8ny^WOTcT4ohAIqh<<@>O!dgkcS;Rbh94sf`%amK-RhNS$c*$iwr z1JXAnN5e;ZPdY|#p1c#9#geAc?@x4qbR0w+dil76bGwoB{INxcqJs(d*Ev7*qphGo zmC(>^?jMogx;jH;HOLMyuA;-X$UHP(kE9vChHwlwfI_o`QD`ZVJSpey!>!`n z-qf$8o76_Pod61LM;Rq|{bgwt64}!7y|G6N|_J5idXmL z0Hu{nz6`Le!QK{WT>zenew1lMjBiSKEVWTkXInPU$qn+J-Vv&&{5t%I^O6DNiNEkt z@S8a4`I1Ug(%#c4T8VHJFrjM|&pydzsxZX9w4GPrlCXi~35)`k*f;6$?B0c*7@Pm5%OB3aC=lmP=}?L8((tqJC5m0Z1wYvQT@7XkJ{cc!mo7*;L|9#%$uB>^(1G2&;^5Yh6vISJ! zR@_4SR^C%VCuyKf^P8n}>5%AZVk+CXS^Pd}qtA0XB(#a5M`0@GT3+8{U?@Dtqe$HeQjX z)7Qpv8v`+2Af4wqVkNOU);~jKb=kbSfG-KsY0^F;^28OINCm1htD$ zabLEMtii_dZaqIzgUyx_(=~R&_V#C{>$z^dh@K;QOqocqBB2@M@imIs(=-m!(fH7A zr(7G4=LDq{Y3+xl6d9Ak8IvX9b3N`~R_R8UJUO2>_p^Lr8>J>#m-JT%2(Bbo-sSIE#fY)ys04ne%B32b8XM)%IK9SegP{Mt&-}V@ILqf}j;kfYv|`2pn!6*uKPxc5ds%+x+V}c~eQjD$fp)ZFhx~9p zy4_M*Nv*wiF`fjwtJv@X(V%z21a|P6aRonpxQ)bP$1sJ%+_GP^kTPz=E$MqBmKfKm zd-dNvGD?Ft9KQ4k?ma6?Xj#I)6i@j@KYT8Ji5fHU&;^W=Z6GGa_=cT1=y`lsN&t_^ z8GY{&@aSrDCHXbW8QPg2zp0<3kSoVM-FtdanJZ~@*ZolC#b+-X!I8OXF3vgBpDVMf z**?_*gxpC3MQyZ?KvyZFiwx(Pa^MF|0k|RFyMf$SvOlVWuN%HDPK2aT$nv4Q30Igx z8g=7&AHv8DCTy2Xb!Pq2x2j+JSQK|tk0jGbfM|2ai(<>lkS8NR82_|3tucrfv+e-qs4^pMY(dVeT5R-Db7-4 z`O)V2&{(&9>-)q($mG}(OH~+8Qy7y!oyxKG!7Io71k1hgA86E7!MaXiN^bOXF9W6` zGx>N_i&zB+tbWUN_cLlxhk{G@7$E)rydPqA@z~csYF?sWCt--*?qX=#O#nDFD8Qk; zp#EK~0EUBTxo{B89tNWA3cbaJewFadZ;SiwZc+0{aWIuYJ-5Eh|A>)8V85LyzzGVx z_g!HlIkjDlidyB+`yhN+zEz@+%NUrrRXq2jO2E0!F%IKFc(MeerE9j#MTCYh^lu-tYNaVj^B2^1bAPWK|Pb+`CUxU=>5XI>!7c*K) z((XBylY^5OO&~KrZ8*&+OGPM8n8W-o7l|H?;1_m*UOwKD3~heA)cgA9=??n$*F+@y z0-7@DD;1k%Uh00gu6GY4#Rgved|&^=q2FZG*PYiYX{-!Tfs) zOHl9by=5esvON-p`rib(1QNSp^>-V z%>XzwmLb?z#)Th5KXKse=Hpiq8Y$JG^tiJ%VzOt~D0h*EwWQ(UcXX7NClR+B z%zP_wVG*R}v4~|dtK<(({;;dHaeke4ac|f^ccPz49vnXRV9w5%RBV=rzFRE2Q_d{E>3R_OLvs`xMZNwRxs{>Lwlj~_ksPdYt}s4*z^fsKCX62r<&n49QL?% z84~2scVisjDf*!fae1-3lZpS~(0ux@P;3%l92ypkLwlSnO?>xybF()0<5CIP84sL8 zBT`ti)7btmhxRb0D;oDB7y!}gnHtWl8BI&tb4M51tq-xje8cS1_Ux+AIF;?H!?hR< z8`j`H77I0gSnPQ%tl0zMd#6bC!<{jU4u|xy9q^?$qIPCW1%FxIfN_c6lyU>=#oM{k ztTEuzHnDQeCiI3dAU#N$HZHjOD~A~)`3I?cYwwC$UueI$)Yv%%_vapY^v$UHGtQTK zcW$Zpeb+1UZjbG9wQN2!I=_-*zO4F?MT#7-`;`V0OyhXb*BvDbz8%Mr=$~i&1){4PuD*Oo+!+A7Jz#pdfqjm7c`jErmGT{ z>#tc}B+JoN95jD#SIKErJ#G4A3GtWI2_Sv(tw^g#Y#NlSJ8iOOkn|vV9+azuyqT}N4QpZa#nLT_#8pV3bUU;GXB3JuF8qT4~`|Bl~=*LiNgKO#^Uf3IS#$7_JyF4o!j(;LtkZ99rC^J-s}S3Z?Ap)+nME z%|eC%hX%E=p#(UzAJ`6*0UH2^MsFY{_jwyEL^Z1?75tjTjjNO+7Wl`MXJu2KGi|CBY@7nLOHc|q?W zB*>{sPAJy1mUWGqfoJduIy*^P!30rXx~0XJ!3pFH=;^Rz1~epi&xGu&k?8An8AT3W zuxuMExw2$D1PS|7uJq`d+Gca&m0rfZQjx|~ap{@5mTd+7We5Xwr9kX7#XgO)w zlcHj=oVVL~MWKcXisq_1s_*;0;*WVuVo_ZhkiM~F+m%UrWVNHpvfU+CXP8DITS0jE zer%%ns%b3N^0z8wM=@HnCk=!|rnZI<9qhhgZerM799$?=L>SKdY0GPayCH0=@W)2? z(wuh)r}(Sc*a&F9DrHY`p_e@mBsLbhlO0_`+sBA;NF7zdY|bC20rGV6M5Fqnv>D>2KuD>AFDezO;~Fekk?t_^O$ zEv0{cT=?GYcDXj`J!zT>Z|3(WlKMYyiCo6gEiFVE1&O&yoN4wIE-IVibi1ir-dc%B z_!@VqpFpNE@_R{Lg``dQRp2VaOhvcQUeta~g4lp=-JWeE$W3^wwsjV+02uI_=W9WxHBX-eug^VeKR}08Xqtb=czI2K3Q0PTk zxmTtIJ6m$fb&H8fe~Gi@ddK~UFX~B=z&N)tM=2acOVH03zmQMk(v8xwrgLH;QL%id z`_X7w(YHch+Mj3VrP9Qxj^WtK>O$Xa08+&9oB*9FGr5YRNNDVQLp@cIA$GjBb(U2 z3q9`mba-dZYfq2<1UknSyxMJ*T>r8gl`ESfp>8!w&T<5k?xP}^T2c;EhB>D=^<%=< zq|Ek-8tkS7_*;Afa#H1X6I+7d5ZgJ6O1gr#@vEOg8D+4k@e8T5XePFZzbkx&Lima!Z z<=$c>vzu%}71No^w^F?@<=U$Xo9%^@&IyyDKmQ|NnS|MBfChVF@TCgm~E3 za#9Tz_h>k6cRw*UtRq|ldv}^A7OnC<=g8M4)DtSV>avV|WuRPyRA9XR?Y@Swg4R`A zjzg$iZ5BYH>1Z&xRlK*Xs{(GKlM0)dqL{s*3dZiqayI08l*BzrqVD%0_oSuwqaSO> zEwQR-?#Q}Y5ltri*s1E%RvP^lUHl#&{PM)Ap1tcN5%@)AAjhB_xQ;JV{*ho(u{~Ox zUGT>ZQx%lDs9V-CcHv3#GKMl34H4W~taNVaKVCZakTe-NgXdTl6h3f;V!Pj)h&Zg(HGYZJ6WXM|{iwPLLoh0OpU)kX z!_L`L(f!1yunA?C6s!kDg|fX+H>S`lbf^oa#pES2hzS(|kq8CfdZ;XPS07_^A5)V) zP}+jGTp8UU5xxHrAAX5buxTVfqsh z`F*K9Y@{GJ8%n7Ztb7_A+9--+Xzz~OF=Hod#7AMJte;&5N=4A_yf;`^AmnKoOO4lB zn!aQqnN-h55`!w$JShqoS=(7g9Ru=meW>v4Yo2z$cP}F3VyOM8&L#Zxs6yo$BHeny zG_K^HGc+^Qr)A+K=4vjgN4nB=*F)$-W)iamo@<5CnvZp`uhErNY+utr)A*Faw@+OB zwuD&~7`@|Aa`(!MqoPy%hXabj3aS%oN>2)n*Tz1@jCDO1(J{UP1Hch73K8m`mu$ga zdljq*YDI><01G0e4AO$VV+)c~4tfeVa8y8GxDl@cii8`Ks-RG~@wx&O4mUW}Kw)sB z?F}dxZiuTR#KV=KD0qu;6~b#l0~7&oajizUpH(B=UuYpTn6;n~xF(?%5fEPo5inZ^ z;dQ?r(el0?(IT#g80+g>L>&Eh2;=)Z#1Qrkpjde1^9E21+=yyK#KAK{#K~(y7;Ntm zMwKx_^Qak-Sf>dhF_jij5IoKoQ^Z(?tqAdVGeqg^+7OBDnjhrI#~a>oH-1Ui8H;VsCH!0529gnl3&n1SyE1cVv613(dA28}Z)5Cbq& z?}u?MKx(2uB#?GzkQ2O*(*+n6CTjnT@PFtEtO2ZL=nEo{x*HkT&Sp^mcFjNC6!fhb&j)1x{0vHC?cW(`-CCtc+1eOA3++PPu z2s3Kef$G8x(I3E^U`9tYFawyOya8+=m@)hc;cl{ta9@Z)XdJeHHGye%w-5oH;}8L_ zwh><7cti{C4x%L?0WlV3BCu|NyXt;3f3X52-wQVXL`2q{dx+7hlYo5#8$==*s4~p> zl8gvxe1HhKkb*Fr4iUyqDnb)*gvjvwh{$wIWWodKH#)}nHbh&*x*3WcwN?dXGh5RE`!6wJf&qvfe?;6oXQ-Elx{tfblX;L^a;mM~|W4eN10PDhjTl_}|%?eOE zF=R{*NR0;yF@QO{hl7Y{VEv)D+m^2YzO@M%2}u+9`uATE@LMYgZ93>7AeQ7pCW8E4 z0b#>EFx4Nad7>a8$pi0AH~uRJz7_>GhyC@~RROVKz{1yG4GP2e8%kN^-_F1a5EDGo z?5{NUDIm&6EF>hu8o&TcS0e9aH@l_;VCW|Mq$FQmndo3e-+3si2MbP`Ya%i zet<|&hV%Y*CVU35!#ziho#P-MT!7B|MSqh~qa%lKyCOofDz@Z7G&TSMTlIeg_o*Nq zuMpX48O=sT1GS6=GQL@XjrzaC4ON3!;N>bvKiy{m-j1A)frMmmV`|$Cf5l7Y$P|#_ z7({sPS9Ps)K8%FDeHd^L>-(#4(*d!;Q!jPK!zf-)Z3Q7tinF|zx`PEv$qy)$5KcXWqPO$l zHYCmy$c^;iuOii{5uwPaLwW?E`35M)fBjW(y+c$+Oq#O{lII0EcS*wrO z#1~b_>Q8|s6b9;ib5)eD{)#0_fmO*%Lad7DgEkZ$zylBPu(+`*0!R>iG)%U?-=z8b zATr4J1`sK{h65Ybea%2wvVeO<^BZoMsQ>H6312kTijYjmNHUPO6vhojLL)LsQhXQ& z&sf2EX=;S@ybbzAhJQ$XsdxBqt?pAp`0lRN~mz;npKRLF$5 z9|D2X4 z@rDPjJlb8z4g@h!@=WnpEx---ZE^GZAj@*Yjm8wj0G~ncpwb!y><7#MoBf}P)Ny1| z$c`VPfcakUgdw=cfXeg!KUENmbPyB#+NJRf+56Ak2g(PY8xqM1^m~x&7l=p>W6$g% z)F(hBQT`h;_Y4pXJR@8khGs}EOpz{dL(yptVu$aQO@N|mgkw;4YwQyR0as16~e7V0mCf-SRV5K-||Rm-EfP~zfA^d%|_I0 z2wK7qzYRlqpnF3`8;ID4!m{qW@E^G-oCY@(H93fyxgB5b<^dU30hb-?8yRaD-|(RA z0`bCYks_ciNeyug0&4Np{Dy=F4D7j=m?$8~ZZ2YG&*CJ|Pl1^=0GGg_0hOfmH zV#D}Ns0?pI;;(@40d_YeOL?IC@SR{4`XnBL8v^Wvb;o}ylE9l(km!6wbqdix-iO~? zqENg2Qw3SFMO@*em{kTK_dp6lML{4c+fh5EVS5 zW-Hpf6dp_xl!F)l6ePu5kV4{n5eeB#r*y&ZSy9kK{;PVx$7$tc@$~8cd?Hr8Y6&cJ z0QQ3^E)tUDjfF9;{^RWgd<25Tl_M&>ak{4Uf7Ua;`;VT0wmhMQ852F3>SkaP#$gmX}xSh z#e}ezfUx1Q9-(4Vpym*vK?1`uq#${yn17n9Va)=h@MaOnsXd4QuBN;NG`q^6LGnvM zLa@ivU_g9tAzUJ1eW;J&eTwjp1v{l63REf&c#9xp?$Ip}M7azY7xr1h0u4~tdLsI2 z%0Ptho6-4*d=K~}P?z)2AR6VsDA$A_3jNqh4_D*qcqapsTu|F$6io_+vp_wVTkP=tR^KmMHg{CoOA{qO0= zpQD<8Pd{J>BmbU$AZ~sBJ^lFi^aFNa_wVV)q3XYBr5pmVZw_{vV!xQ2pmP3Jo}0M?(6J{2jUN6!@JS1vc=%{||sg85RHl delta 37746 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 Date: Fri, 19 Jul 2019 21:19:09 -0400 Subject: [PATCH 277/366] Don't load old adapters. --- .../src/main/resources/worldedit-adapters.jar | Bin 857125 -> 857125 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index 1dfbc9f9a8037215f08fa2a500dd5a9840d35e02..d1659adf24c493d50954aa4767a0ce884cf8a0fe 100644 GIT binary patch delta 24947 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 VJq-kY*+wca+bH$_eH)R&{2%WIS=9gl delta 24947 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 d>k%+f5Mkx{{XpCFHryh From edb2e919e793470b22631157ec4e8bdda8f034de Mon Sep 17 00:00:00 2001 From: wizjany Date: Fri, 19 Jul 2019 21:45:25 -0400 Subject: [PATCH 278/366] Add more id conversions. Bukkit apparently lower cases these for us, but not Forge. (And invalid block entities are fine - invalid keys are not). --- .../extent/clipboard/io/MCEditSchematicReader.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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 f3180df2d..61110ea09 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 @@ -384,6 +384,20 @@ public class MCEditSchematicReader extends NBTSchematicReader { return "chest"; case "Sign": return "sign"; + case "Banner": + return "banner"; + case "Beacon": + return "beacon"; + case "Comparator": + return "comparator"; + case "Dropper": + return "dropper"; + case "Furnace": + return "furnace"; + case "Hopper": + return "hopper"; + case "Skull": + return "skull"; default: return id; } From 5c2b9e4157b322247607b2e175ab30d6c83a02e7 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 22 Jul 2019 21:18:52 +1000 Subject: [PATCH 279/366] 7.0.1 RC1 --- CHANGELOG.txt | 24 ++++++++++++++++++++++++ gradle.properties | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c49cdaaca..afa6f8601 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,27 @@ +7.0.1 Release Candidate 1 +- Improve //naturalize over large areas +- Fixed //restore with 1.14 worlds +- Added item brush support to WorldEdit for Bukkit (Formerly just Forge) +- Create an internal state ID mapping for performance +- Improve rotation for some blocks +- Added .self permission node to undo/redo to only allow undoing and redoing own history +- Improve sponge schematic implementation +- Re-add the delchunks command +- Added 1.14 blocks, items, tags, etc to the API (Remains compatible with 1.13) +- Made the navigation and selection wands normal tools that can be rebound per-user with //selwand and //navwand +- Added //wand -n to get the navigation wand +- Improved movement of paintings +- Allow command suggestions for selectors +- Allow block replacer to work with tile entities +- Fixed pasting leashed entities +- Fixed setting player heads with names +- Added a mask flag to //count +- Setup pagination for //distr +- Fixed an entity-related error being caused by plugins improperly using Spigot. +- Fixed gravity brush +- Modify chunk batching for performance +- Further legacy schematic loading improvements + 7.0.0 See https://matthewmiller.dev/blog/introducing-worldedit-7/ for a friendlier explanation of some new features diff --git a/gradle.properties b/gradle.properties index a2cc53d8e..d6e9d6737 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ group=com.sk89q.worldedit -version=7.0.1-SNAPSHOT +version=7.0.1-rc1 org.gradle.jvmargs=-Xmx1G From c3e3ae49566708911673a7b1056ebe7e2350ae84 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 22 Jul 2019 21:19:04 +1000 Subject: [PATCH 280/366] Back to snapshots --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d6e9d6737..a2cc53d8e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ group=com.sk89q.worldedit -version=7.0.1-rc1 +version=7.0.1-SNAPSHOT org.gradle.jvmargs=-Xmx1G From 449b0991f33e794a90f13cb7b0bfe57cd193ac82 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 22 Jul 2019 21:20:40 +1000 Subject: [PATCH 281/366] Bump to Piston 0.4.3 --- buildSrc/src/main/kotlin/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 4679c2d40..e0c2b4763 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,7 +1,7 @@ object Versions { const val TEXT = "3.0.1" const val TEXT_EXTRAS = "3.0.2" - const val PISTON = "0.4.2" + const val PISTON = "0.4.3" const val AUTO_VALUE = "1.6.5" const val JUNIT = "5.5.0" } From a9b3fb14298f6c73073385c7ff87d08da175f590 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 22 Jul 2019 22:24:45 +1000 Subject: [PATCH 282/366] Fixed tile entity interaction with Fabric --- .../sk89q/worldedit/fabric/FabricWorld.java | 14 +++- .../worldedit/fabric/TileEntityUtils.java | 79 ------------------- 2 files changed, 10 insertions(+), 83 deletions(-) delete mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java index afc6cc99e..93d14b753 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java @@ -202,9 +202,13 @@ public class FabricWorld extends AbstractWorld { CompoundTag tag = ((BaseBlock) block).getNbtData(); if (tag != null) { net.minecraft.nbt.CompoundTag nativeTag = NBTConverter.toNative(tag); - nativeTag.putString("id", ((BaseBlock) block).getNbtId()); - TileEntityUtils.setTileEntity(world, position, nativeTag); - successful = true; // update if TE changed as well + BlockEntity tileEntity = getWorld().getWorldChunk(pos).getBlockEntity(pos); + if (tileEntity != null) { + tileEntity.fromTag(nativeTag); + tileEntity.setPos(pos); + tileEntity.setWorld(world); + successful = true; // update if TE changed as well + } } } } @@ -503,7 +507,9 @@ public class FabricWorld extends AbstractWorld { BlockEntity tile = ((WorldChunk) getWorld().getChunk(pos)).getBlockEntity(pos, WorldChunk.CreationType.CHECK); if (tile != null) { - return getBlock(position).toBaseBlock(NBTConverter.fromNative(TileEntityUtils.copyNbtData(tile))); + net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag(); + tile.toTag(tag); + return getBlock(position).toBaseBlock(NBTConverter.fromNative(tag)); } else { return getBlock(position).toBaseBlock(); } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java deleted file mode 100644 index 4faec9d9e..000000000 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/TileEntityUtils.java +++ /dev/null @@ -1,79 +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 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.fabric; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.sk89q.worldedit.math.BlockVector3; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.IntTag; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import javax.annotation.Nullable; - -/** - * Utility methods for setting tile entities in the world. - */ -final class TileEntityUtils { - - private TileEntityUtils() { - } - - /** - * Update the given tag compound with position information. - * - * @param tag the tag - * @param position the position - */ - private static void updateForSet(CompoundTag tag, BlockVector3 position) { - checkNotNull(tag); - checkNotNull(position); - - tag.put("x", new IntTag(position.getBlockX())); - tag.put("y", new IntTag(position.getBlockY())); - tag.put("z", new IntTag(position.getBlockZ())); - } - - /** - * Set a tile entity at the given location using the tile entity ID from - * the tag. - * - * @param world the world - * @param position the position - * @param tag the tag for the tile entity (may be null to do nothing) - */ - static void setTileEntity(World world, BlockVector3 position, @Nullable CompoundTag tag) { - if (tag != null) { - updateForSet(tag, position); - BlockEntity tileEntity = BlockEntity.createFromTag(tag); - if (tileEntity != null) { - world.setBlockEntity(new BlockPos(position.getBlockX(), position.getBlockY(), position.getBlockZ()), tileEntity); - } - } - } - - public static CompoundTag copyNbtData(BlockEntity tile) { - CompoundTag tag = new CompoundTag(); - tile.toTag(tag); - return tag; - } -} From 917f8a18420e30da17e6784a1b20316a6aae35f4 Mon Sep 17 00:00:00 2001 From: Wyatt Childers Date: Sat, 29 Jun 2019 17:52:40 -0400 Subject: [PATCH 283/366] Pass through wall improvements This change simplifies the algorithm greatly. Additionally, this fixes a bug where if standing in a non-solid block i.e. a glass pane, //thru, and the nav wand would not work. --- .../platform/AbstractPlayerActor.java | 91 +++++++++++-------- 1 file changed, 51 insertions(+), 40 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index f51f992ac..c25c33f39 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -394,51 +394,62 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { } } + private boolean canPassThroughBlock(Location curBlock) { + BlockVector3 blockPos = curBlock.toVector().toBlockPoint(); + BlockState block = curBlock.getExtent().getBlock(blockPos); + return !block.getBlockType().getMaterial().isMovementBlocker(); + } + /** - * Get the player's view yaw. - * - * @return yaw + * Advances the block target block until the current block is a wall + * @return true if a wall is found */ - - @Override - public boolean passThroughForwardWall(int range) { - int searchDist = 0; - TargetBlock hitBlox = new TargetBlock(this, range, 0.2); - Extent world = getLocation().getExtent(); - Location block; - boolean firstBlock = true; - int freeToFind = 2; - boolean inFree = false; - - while ((block = hitBlox.getNextBlock()) != null) { - boolean free = !world.getBlock(block.toVector().toBlockPoint()).getBlockType().getMaterial().isMovementBlocker(); - - if (firstBlock) { - firstBlock = false; - - if (!free) { - --freeToFind; - continue; - } - } - - ++searchDist; - if (searchDist > 20) { - return false; - } - - if (inFree != free) { - if (free) { - --freeToFind; - } - } - - if (freeToFind == 0) { - setOnGround(block); + private boolean advanceToWall(TargetBlock hitBlox) { + Location curBlock; + while ((curBlock = hitBlox.getCurrentBlock()) != null) { + if (!canPassThroughBlock(curBlock)) { return true; } - inFree = free; + hitBlox.getNextBlock(); + } + + return false; + } + + /** + * Advances the block target block until the current block is a free + * @return true if a free spot is found + */ + private boolean advanceToFree(TargetBlock hitBlox) { + Location curBlock; + while ((curBlock = hitBlox.getCurrentBlock()) != null) { + if (canPassThroughBlock(curBlock)) { + return true; + } + + hitBlox.getNextBlock(); + } + + return false; + } + + @Override + public boolean passThroughForwardWall(int range) { + TargetBlock hitBlox = new TargetBlock(this, range, 0.2); + + if (!advanceToWall(hitBlox)) { + return false; + } + + if (!advanceToFree(hitBlox)) { + return false; + } + + Location foundBlock = hitBlox.getCurrentBlock(); + if (foundBlock != null) { + setOnGround(foundBlock); + return true; } return false; From e504c29df672c32f2baf851def5647492b2e2297 Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 23 Jul 2019 21:41:13 -0400 Subject: [PATCH 284/366] Fix potential race condition. I guess. --- .../main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 977985df7..438c43cbd 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 @@ -316,15 +316,16 @@ public class BukkitWorld extends AbstractWorld { @Override public boolean equals(Object other) { - if (worldRef.get() == null) { + final World ref = worldRef.get(); + if (ref == null) { return false; } else if (other == null) { return false; } else if ((other instanceof BukkitWorld)) { World otherWorld = ((BukkitWorld) other).worldRef.get(); - return otherWorld != null && otherWorld.equals(getWorld()); + return ref.equals(otherWorld); } else if (other instanceof com.sk89q.worldedit.world.World) { - return ((com.sk89q.worldedit.world.World) other).getName().equals(getName()); + return ((com.sk89q.worldedit.world.World) other).getName().equals(ref.getName()); } else { return false; } From 8545417b3a4c926d204a8972493ff1a3c83a0ec9 Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 10 Jul 2019 18:25:34 -0400 Subject: [PATCH 285/366] Fix error in /up when used out of bounds. Also reduce calls to Entity#getLocation() all over since it's more expensive than it needs to be (adapts world/vector every time). --- .../worldedit/command/BiomeCommands.java | 3 +- .../platform/AbstractPlayerActor.java | 41 +++++++++++++------ .../extension/platform/PlayerProxy.java | 5 +++ .../clipboard/io/SpongeSchematicWriter.java | 5 ++- .../internal/cui/ServerCUIHandler.java | 10 +++-- .../sk89q/worldedit/fabric/FabricPlayer.java | 16 +++++++- .../sk89q/worldedit/forge/ForgePlayer.java | 16 +++++++- .../sk89q/worldedit/sponge/SpongePlayer.java | 12 ++++++ 8 files changed, 86 insertions(+), 22 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java index 4e2b714e2..29747852e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BiomeCommands.java @@ -180,7 +180,8 @@ public class BiomeCommands { Mask2D mask2d = mask != null ? mask.toMask2D() : null; if (atPosition) { - region = new CuboidRegion(player.getLocation().toVector().toBlockPoint(), player.getLocation().toVector().toBlockPoint()); + final BlockVector3 pos = player.getLocation().toVector().toBlockPoint(); + region = new CuboidRegion(pos, pos); } else { region = session.getSelection(world); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index f51f992ac..cea7d8d47 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -19,7 +19,10 @@ package com.sk89q.worldedit.extension.platform; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.NotABlockException; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.Extent; @@ -32,6 +35,7 @@ import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TargetBlock; import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -173,7 +177,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { if (spots == 2) { final BlockVector3 platform = BlockVector3.at(x, y - 2, z); final BlockState block = world.getBlock(platform); - final com.sk89q.worldedit.world.block.BlockType type = block.getBlockType(); + final BlockType type = block.getBlockType(); // Don't get put in lava! if (type == BlockTypes.LAVA) { @@ -259,6 +263,13 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { // Found a ceiling! if (world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) { int platformY = Math.max(initialY, y - 3 - clearance); + if (platformY < initialY) { // if ==, they already have the given clearance, if <, clearance is too large + printError("Not enough space above you!"); + return false; + } else if (platformY == initialY) { + printError("You're already at the ceiling."); + return false; + } floatAt(x, platformY + 1, z, alwaysGlass); return true; } @@ -302,25 +313,27 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public void floatAt(int x, int y, int z, boolean alwaysGlass) { - try { - BlockVector3 spot = BlockVector3.at(x, y - 1, z); - if (!getLocation().getExtent().getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) { - getLocation().getExtent().setBlock(spot, BlockTypes.GLASS.getDefaultState()); + BlockVector3 spot = BlockVector3.at(x, y - 1, z); + final World world = (World) getLocation().getExtent(); + if (!world.getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) { + try (EditSession session = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, 1, this)) { + session.setBlock(spot, BlockTypes.GLASS.getDefaultState()); + } catch (MaxChangedBlocksException ignored) { } - } catch (WorldEditException e) { - e.printStackTrace(); } setPosition(Vector3.at(x + 0.5, y, z + 0.5)); } @Override public Location getBlockIn() { - return getLocation().setPosition(getLocation().toVector().floor()); + final Location location = getLocation(); + return location.setPosition(location.toVector().floor()); } @Override public Location getBlockOn() { - return getLocation().setPosition(getLocation().setY(getLocation().getY() - 1).toVector().floor()); + final Location location = getLocation(); + return location.setPosition(location.setY(location.getY() - 1).toVector().floor()); } @Override @@ -369,15 +382,16 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public Direction getCardinalDirection(int yawOffset) { - if (getLocation().getPitch() > 67.5) { + final Location location = getLocation(); + if (location.getPitch() > 67.5) { return Direction.DOWN; } - if (getLocation().getPitch() < -67.5) { + if (location.getPitch() < -67.5) { return Direction.UP; } // From hey0's code - double rot = (getLocation().getYaw() + yawOffset) % 360; //let's use real yaw now + double rot = (location.getYaw() + yawOffset) % 360; //let's use real yaw now if (rot < 0) { rot += 360.0; } @@ -446,7 +460,8 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public void setPosition(Vector3 pos) { - setPosition(pos, getLocation().getPitch(), getLocation().getYaw()); + final Location location = getLocation(); + setPosition(pos, location.getPitch(), location.getYaw()); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java index 8ecf3cc10..120dd47ac 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java @@ -178,4 +178,9 @@ class PlayerProxy extends AbstractPlayerActor { public > void sendFakeBlock(BlockVector3 pos, B block) { basePlayer.sendFakeBlock(pos, block); } + + @Override + public void floatAt(int x, int y, int z, boolean alwaysGlass) { + basePlayer.floatAt(x, y, z, alwaysGlass); + } } 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 2ed06cc03..fcc8c8e93 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 @@ -260,8 +260,9 @@ public class SpongeSchematicWriter implements ClipboardWriter { } values.remove("id"); values.put("Id", new StringTag(state.getType().getId())); - values.put("Pos", writeVector(e.getLocation().toVector())); - values.put("Rotation", writeRotation(e.getLocation())); + final Location location = e.getLocation(); + values.put("Pos", writeVector(location.toVector())); + values.put("Rotation", writeRotation(location)); return new CompoundTag(values); }).filter(Objects::nonNull).collect(Collectors.toList()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java index 5a13140db..2ca8f3bd3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/cui/ServerCUIHandler.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockTypes; @@ -114,11 +115,12 @@ public class ServerCUIHandler { } // Borrowed this math from FAWE - double rotX = player.getLocation().getYaw(); - double rotY = player.getLocation().getPitch(); + final Location location = player.getLocation(); + double rotX = location.getYaw(); + double rotY = location.getPitch(); double xz = Math.cos(Math.toRadians(rotY)); - int x = (int) (player.getLocation().getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12); - int z = (int) (player.getLocation().getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12); + int x = (int) (location.getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12); + int z = (int) (location.getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12); int y = Math.max(0, Math.min(Math.min(255, posY + 32), posY + 3)); Map structureTag = new HashMap<>(); diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java index d96e0f81f..2d0681c1b 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java @@ -106,7 +106,7 @@ public class FabricPlayer extends AbstractPlayerActor { } @Override - public com.sk89q.worldedit.world.World getWorld() { + public World getWorld() { return FabricWorldEdit.inst.getWorld(this.player.world); } @@ -188,6 +188,20 @@ public class FabricPlayer extends AbstractPlayerActor { return null; } + @Override + public void floatAt(int x, int y, int z, boolean alwaysGlass) { + if (alwaysGlass || !player.abilities.allowFlying) { + super.floatAt(x, y, z, alwaysGlass); + return; + } + + setPosition(Vector3.at(x + 0.5, y, z + 0.5)); + if (!player.abilities.flying) { + player.abilities.flying = true; + player.sendAbilitiesUpdate(); + } + } + @Override public > void sendFakeBlock(BlockVector3 pos, B block) { World world = getWorld(); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index a48ff6256..e55761da3 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -107,7 +107,7 @@ public class ForgePlayer extends AbstractPlayerActor { } @Override - public com.sk89q.worldedit.world.World getWorld() { + public World getWorld() { return ForgeWorldEdit.inst.getWorld(this.player.world); } @@ -189,6 +189,20 @@ public class ForgePlayer extends AbstractPlayerActor { return null; } + @Override + public void floatAt(int x, int y, int z, boolean alwaysGlass) { + if (alwaysGlass || !player.abilities.allowFlying) { + super.floatAt(x, y, z, alwaysGlass); + return; + } + + setPosition(Vector3.at(x + 0.5, y, z + 0.5)); + if (!player.abilities.isFlying) { + player.abilities.isFlying = true; + player.sendPlayerAbilities(); + } + } + @Override public > void sendFakeBlock(BlockVector3 pos, B block) { World world = getWorld(); diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java index 82723fe93..45fc43000 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java @@ -38,6 +38,7 @@ import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemTypes; import org.spongepowered.api.Sponge; +import org.spongepowered.api.data.key.Keys; import org.spongepowered.api.data.type.HandTypes; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.item.ItemType; @@ -202,6 +203,17 @@ public class SpongePlayer extends AbstractPlayerActor { gameMode.getId()).get()); } + @Override + public void floatAt(int x, int y, int z, boolean alwaysGlass) { + if (alwaysGlass || !player.get(Keys.CAN_FLY).orElse(false)) { + super.floatAt(x, y, z, alwaysGlass); + return; + } + + setPosition(Vector3.at(x + 0.5, y, z + 0.5)); + player.offer(Keys.IS_FLYING, true); + } + @Override public > void sendFakeBlock(BlockVector3 pos, B block) { org.spongepowered.api.world.Location loc = player.getWorld().getLocation(pos.getX(), pos.getY(), pos.getZ()); From 2cc6a367c623183200ee59b3e6e337315ce67290 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 11 Jul 2019 20:27:05 -0400 Subject: [PATCH 286/366] Move floatAt logic to AbstractPlayer, add isAllowedToFly and setFlying. --- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 13 ++++++------- .../com/sk89q/worldedit/entity/Player.java | 18 ++++++++++++++++++ .../platform/AbstractPlayerActor.java | 16 ++++++++++------ .../sk89q/worldedit/fabric/FabricPlayer.java | 15 +++++++-------- .../com/sk89q/worldedit/forge/ForgePlayer.java | 15 +++++++-------- .../sk89q/worldedit/sponge/SpongePlayer.java | 13 ++++++------- 6 files changed, 54 insertions(+), 36 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index b5cd6bd37..3e12279ea 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -185,14 +185,13 @@ public class BukkitPlayer extends AbstractPlayerActor { } @Override - public void floatAt(int x, int y, int z, boolean alwaysGlass) { - if (alwaysGlass || !player.getAllowFlight()) { - super.floatAt(x, y, z, alwaysGlass); - return; - } + public boolean isAllowedToFly() { + return player.getAllowFlight(); + } - setPosition(Vector3.at(x + 0.5, y, z + 0.5)); - player.setFlying(true); + @Override + public void setFlying(boolean flying) { + player.setFlying(flying); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java index 3673d8842..a51864ee4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -187,6 +187,24 @@ public interface Player extends Entity, Actor { */ void floatAt(int x, int y, int z, boolean alwaysGlass); + /** + * Check whether the player is allowed to fly. + * + * @return true if allowed flight + */ + default boolean isAllowedToFly() { + return false; + } + + /** + * Set whether the player is currently flying. + * + * @param flying true to fly + */ + default void setFlying(boolean flying) { + throw new UnsupportedOperationException("setFlying unimplemented but isAllowedToFly was true (or unchecked)"); + } + /** * Get the point of the block that is being stood in. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index cea7d8d47..fb70c77ba 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -313,13 +313,17 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public void floatAt(int x, int y, int z, boolean alwaysGlass) { - BlockVector3 spot = BlockVector3.at(x, y - 1, z); - final World world = (World) getLocation().getExtent(); - if (!world.getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) { - try (EditSession session = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, 1, this)) { - session.setBlock(spot, BlockTypes.GLASS.getDefaultState()); - } catch (MaxChangedBlocksException ignored) { + if (alwaysGlass || !isAllowedToFly()) { + BlockVector3 spot = BlockVector3.at(x, y - 1, z); + final World world = getWorld(); + if (!world.getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) { + try (EditSession session = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, 1, this)) { + session.setBlock(spot, BlockTypes.GLASS.getDefaultState()); + } catch (MaxChangedBlocksException ignored) { + } } + } else { + setFlying(true); } setPosition(Vector3.at(x + 0.5, y, z + 0.5)); } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java index 2d0681c1b..6bd1171d7 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java @@ -189,15 +189,14 @@ public class FabricPlayer extends AbstractPlayerActor { } @Override - public void floatAt(int x, int y, int z, boolean alwaysGlass) { - if (alwaysGlass || !player.abilities.allowFlying) { - super.floatAt(x, y, z, alwaysGlass); - return; - } + public boolean isAllowedToFly() { + return player.abilities.allowFlying; + } - setPosition(Vector3.at(x + 0.5, y, z + 0.5)); - if (!player.abilities.flying) { - player.abilities.flying = true; + @Override + public void setFlying(boolean flying) { + if (player.abilities.flying != flying) { + player.abilities.flying = flying; player.sendAbilitiesUpdate(); } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index e55761da3..94dfb8c10 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -190,15 +190,14 @@ public class ForgePlayer extends AbstractPlayerActor { } @Override - public void floatAt(int x, int y, int z, boolean alwaysGlass) { - if (alwaysGlass || !player.abilities.allowFlying) { - super.floatAt(x, y, z, alwaysGlass); - return; - } + public boolean isAllowedToFly() { + return player.abilities.allowFlying; + } - setPosition(Vector3.at(x + 0.5, y, z + 0.5)); - if (!player.abilities.isFlying) { - player.abilities.isFlying = true; + @Override + public void setFlying(boolean flying) { + if (player.abilities.isFlying != flying) { + player.abilities.isFlying = flying; player.sendPlayerAbilities(); } } diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java index 45fc43000..3a5f94933 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java @@ -204,14 +204,13 @@ public class SpongePlayer extends AbstractPlayerActor { } @Override - public void floatAt(int x, int y, int z, boolean alwaysGlass) { - if (alwaysGlass || !player.get(Keys.CAN_FLY).orElse(false)) { - super.floatAt(x, y, z, alwaysGlass); - return; - } + public boolean isAllowedToFly() { + return player.get(Keys.CAN_FLY).orElse(super.isAllowedToFly()); + } - setPosition(Vector3.at(x + 0.5, y, z + 0.5)); - player.offer(Keys.IS_FLYING, true); + @Override + public void setFlying(boolean flying) { + player.offer(Keys.IS_FLYING, flying); } @Override From 4ee2d3b47cef5b17898702f7bc6a031b6b206523 Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 16 Jul 2019 22:17:19 -0400 Subject: [PATCH 287/366] Move isAllowedToFly and setFlying to AbstractPlayer, protect them. --- .../com/sk89q/worldedit/entity/Player.java | 18 ------------------ .../platform/AbstractPlayerActor.java | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java index a51864ee4..3673d8842 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -187,24 +187,6 @@ public interface Player extends Entity, Actor { */ void floatAt(int x, int y, int z, boolean alwaysGlass); - /** - * Check whether the player is allowed to fly. - * - * @return true if allowed flight - */ - default boolean isAllowedToFly() { - return false; - } - - /** - * Set whether the player is currently flying. - * - * @param flying true to fly - */ - default void setFlying(boolean flying) { - throw new UnsupportedOperationException("setFlying unimplemented but isAllowedToFly was true (or unchecked)"); - } - /** * Get the point of the block that is being stood in. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index fb70c77ba..9c9319e58 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -328,6 +328,24 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { setPosition(Vector3.at(x + 0.5, y, z + 0.5)); } + /** + * Check whether the player is allowed to fly. + * + * @return true if allowed flight + */ + protected boolean isAllowedToFly() { + return false; + } + + /** + * Set whether the player is currently flying. + * + * @param flying true to fly + */ + protected void setFlying(boolean flying) { + } + + @Override public Location getBlockIn() { final Location location = getLocation(); From 415cdc0ab2a8f2dd5d1439cf46e8e7a15a53a3ae Mon Sep 17 00:00:00 2001 From: wizjany Date: Wed, 24 Jul 2019 19:05:39 -0400 Subject: [PATCH 288/366] Output to debug only if we have a valid DFU for schematics. Warn for backwards (since we can't DFU) and info for missing DFU (since it might still be compatible). Under normal circumstances, a DFU should be available so we'll only log to debug (which is generally off). --- .../worldedit/extent/clipboard/io/SpongeSchematicReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 865dae6fd..b2deb51f0 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 @@ -111,7 +111,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { } else if (dataVersion < liveDataVersion) { fixer = platform.getDataFixer(); if (fixer != null) { - log.info("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.", + log.debug("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.", dataVersion, liveDataVersion); } else { log.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.", From c8cf0d8ba64ced99dbe18063caa7ba80b6cbbd03 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 25 Jul 2019 19:19:03 -0700 Subject: [PATCH 289/366] [Forge] Update to 1.14.4, pending Forge bugfixes --- worldedit-forge/build.gradle.kts | 9 ++++----- .../java/com/sk89q/worldedit/forge/ForgePlatform.java | 2 +- .../java/com/sk89q/worldedit/forge/ForgeWorld.java | 10 +++++----- .../com/sk89q/worldedit/forge/WorldEditFakePlayer.java | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index 235900181..89ae7fc27 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -11,8 +11,9 @@ plugins { applyPlatformAndCoreConfiguration() applyShadowConfiguration() -val minecraftVersion = "1.14.3" -val forgeVersion = "27.0.13" +val minecraftVersion = "1.14.4" +val mappingsMinecraftVersion = "1.14.3" +val forgeVersion = "28.0.16" configurations.all { resolutionStrategy { @@ -25,14 +26,12 @@ dependencies { "compile"("org.apache.logging.log4j:log4j-slf4j-impl:2.11.2") "minecraft"("net.minecraftforge:forge:$minecraftVersion-$forgeVersion") - - "testCompile"("org.mockito:mockito-core:1.9.0-rc1") } configure { mappings(mapOf( "channel" to "snapshot", - "version" to "20190626-$minecraftVersion" + "version" to "20190724-$mappingsMinecraftVersion" )) runs { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 99ef0103e..93fea255f 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -35,7 +35,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.management.PlayerList; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SharedConstants; -import net.minecraft.world.ServerWorld; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.fml.server.ServerLifecycleHooks; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index dca8f1c1f..542cf884c 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -65,13 +65,11 @@ import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.ServerWorld; import net.minecraft.world.World; import net.minecraft.world.chunk.AbstractChunkProvider; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.IChunk; -import net.minecraft.world.chunk.ServerChunkProvider; import net.minecraft.world.chunk.listener.IChunkStatusListener; import net.minecraft.world.gen.feature.BigBrownMushroomFeature; import net.minecraft.world.gen.feature.BigMushroomFeatureConfig; @@ -91,6 +89,8 @@ import net.minecraft.world.gen.feature.ShrubFeature; import net.minecraft.world.gen.feature.SwampTreeFeature; import net.minecraft.world.gen.feature.TallTaigaTreeFeature; import net.minecraft.world.gen.feature.TreeFeature; +import net.minecraft.world.server.ServerChunkProvider; +import net.minecraft.world.server.ServerWorld; import net.minecraft.world.storage.SaveHandler; import net.minecraft.world.storage.WorldInfo; @@ -583,15 +583,15 @@ public class ForgeWorld extends AbstractWorld { private static class NoOpChunkStatusListener implements IChunkStatusListener { @Override - public void func_219509_a(ChunkPos chunkPos) { + public void start(ChunkPos chunkPos) { } @Override - public void func_219508_a(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) { + public void statusChanged(ChunkPos chunkPos, @Nullable ChunkStatus chunkStatus) { } @Override - public void func_219510_b() { + public void stop() { } } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java index 53897176e..971179339 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/WorldEditFakePlayer.java @@ -21,7 +21,7 @@ package com.sk89q.worldedit.forge; import com.mojang.authlib.GameProfile; import net.minecraft.inventory.container.INamedContainerProvider; -import net.minecraft.world.ServerWorld; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.FakePlayer; import javax.annotation.Nullable; From 8f33e0d550fa63365b4cf1f94ebeec677acb4f43 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 27 Jul 2019 00:35:38 -0400 Subject: [PATCH 290/366] Make a bunch of paginations internal, generify command boxes. (#509) --- .../worldedit/command/ChunkCommands.java | 39 ++++++-- .../worldedit/command/SchematicCommands.java | 46 +++++++++- .../worldedit/command/SelectionCommands.java | 66 +++++++++++++- .../worldedit/command/UtilityCommands.java | 3 +- .../worldedit/command/WorldEditCommands.java | 3 +- .../command/util/PrintCommandHelp.java | 19 ++-- .../component/BlockDistributionResult.java | 90 ------------------- .../formatting/component/CommandListBox.java | 8 +- .../formatting/component/CommandUsageBox.java | 16 ++-- .../component/SchematicPaginationBox.java | 75 ---------------- 10 files changed, 170 insertions(+), 195 deletions(-) delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index e9a9e231d..5d5d245d1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; +import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.internal.anvil.ChunkDeleter; import com.sk89q.worldedit.internal.anvil.ChunkDeletionInfo; @@ -34,6 +35,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.formatting.component.PaginationBox; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; @@ -50,8 +52,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.ArrayList; +import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; @@ -93,11 +95,11 @@ public class ChunkCommands { @CommandPermissions("worldedit.listchunks") public void listChunks(Player player, LocalSession session, @ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException { - Set chunks = session.getSelection(player.getWorld()).getChunks(); + final Region region = session.getSelection(player.getWorld()); - PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks -p %page%", - chunks.stream().map(BlockVector2::toString).collect(Collectors.toList())); - player.print(paginationBox.create(page)); + WorldEditAsyncCommandBuilder.createAndSendMessage(player, + () -> new ChunkListPaginationBox(region).create(page), + "Listing chunks for " + player.getName()); } @Command( @@ -134,8 +136,8 @@ public class ChunkCommands { newBatch.backup = true; final Region selection = session.getSelection(player.getWorld()); if (selection instanceof CuboidRegion) { - newBatch.minChunk = BlockVector2.at(selection.getMinimumPoint().getBlockX() >> 4, selection.getMinimumPoint().getBlockZ() >> 4); - newBatch.maxChunk = BlockVector2.at(selection.getMaximumPoint().getBlockX() >> 4, selection.getMaximumPoint().getBlockZ() >> 4); + newBatch.minChunk = selection.getMinimumPoint().shr(4).toBlockVector2(); + newBatch.maxChunk = selection.getMaximumPoint().shr(4).toBlockVector2(); } else { // this has a possibility to OOM for very large selections still Set chunks = selection.getChunks(); @@ -168,4 +170,27 @@ public class ChunkCommands { .clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop")))); } + private static class ChunkListPaginationBox extends PaginationBox { + //private final Region region; + private final List chunks; + + ChunkListPaginationBox(Region region) { + super("Selected Chunks", "/listchunks -p %page%"); + // TODO make efficient/streamable/calculable implementations of this + // for most region types, so we can just store the region and random-access get one page of chunks + // (this is non-trivial for some types of selections...) + //this.region = region.clone(); + this.chunks = new ArrayList<>(region.getChunks()); + } + + @Override + public Component getComponent(int number) { + return TextComponent.of(chunks.get(number).toString()); + } + + @Override + public int getComponentsSize() { + return chunks.size(); + } + } } 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 47f3daf9e..a2b59ffbd 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 @@ -19,6 +19,8 @@ package com.sk89q.worldedit.command; +import com.google.common.collect.Multimap; +import com.google.common.io.Files; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -42,10 +44,10 @@ import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.formatting.component.CodeFormat; import com.sk89q.worldedit.util.formatting.component.ErrorFormat; import com.sk89q.worldedit.util.formatting.component.PaginationBox; -import com.sk89q.worldedit.util.formatting.component.SchematicPaginationBox; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.io.file.FilenameException; @@ -68,7 +70,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; +import java.util.regex.Pattern; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -404,4 +408,44 @@ public class SchematicCommands { } return fileList; } + + private static class SchematicPaginationBox extends PaginationBox { + private final String prefix; + private final File[] files; + + SchematicPaginationBox(String rootDir, File[] files, String pageCommand) { + super("Available schematics", pageCommand); + this.prefix = rootDir == null ? "" : rootDir; + this.files = files; + } + + @Override + public Component getComponent(int number) { + checkArgument(number < files.length && number >= 0); + File file = files[number]; + Multimap exts = ClipboardFormats.getFileExtensionMap(); + String format = exts.get(Files.getFileExtension(file.getName())) + .stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown"); + boolean inRoot = file.getParentFile().getName().equals(prefix); + + String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1]; + + return TextComponent.builder() + .content("") + .append(TextComponent.of("[L]") + .color(TextColor.GOLD) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load " + path)) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load")))) + .append(TextComponent.space()) + .append(TextComponent.of(path) + .color(TextColor.DARK_GREEN) + .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format)))) + .build(); + } + + @Override + public int getComponentsSize() { + return files.length; + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index d0dd6ef5a..88285e475 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.command; +import com.google.common.base.Strings; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -56,16 +57,19 @@ import com.sk89q.worldedit.regions.selector.SphereRegionSelector; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.util.formatting.component.BlockDistributionResult; import com.sk89q.worldedit.util.formatting.component.CommandListBox; +import com.sk89q.worldedit.util.formatting.component.InvalidComponentException; import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.component.SubtleFormat; import com.sk89q.worldedit.util.formatting.component.TextComponentProducer; +import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.storage.ChunkStore; @@ -570,7 +574,7 @@ public class SelectionCommands { } case LIST: default: - CommandListBox box = new CommandListBox("Selection modes", null); + CommandListBox box = new CommandListBox("Selection modes", null, null); box.setHidingHelp(true); TextComponentProducer contents = box.getContents(); contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline(); @@ -608,4 +612,62 @@ public class SelectionCommands { session.dispatchCUISelection(player); } + private static class BlockDistributionResult extends PaginationBox { + + private final List> distribution; + private final int totalBlocks; + private final boolean separateStates; + + BlockDistributionResult(List> distribution, boolean separateStates) { + super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : "")); + this.distribution = distribution; + // note: doing things like region.getArea is inaccurate for non-cuboids. + this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum(); + this.separateStates = separateStates; + setComponentsPerPage(7); + } + + @Override + public Component getComponent(int number) { + Countable c = distribution.get(number); + TextComponent.Builder line = TextComponent.builder(); + + final int count = c.getAmount(); + + final double perc = count / (double) totalBlocks * 100; + final int maxDigits = (int) (Math.log10(totalBlocks) + 1); + final int curDigits = (int) (Math.log10(count) + 1); + line.append(String.format("%s%.3f%% ", perc < 10 ? " " : "", perc), TextColor.GOLD); + final int space = maxDigits - curDigits; + String pad = Strings.repeat(" ", space == 0 ? 2 : 2 * space + 1); + line.append(String.format("%s%s", count, pad), TextColor.YELLOW); + + final BlockState state = c.getID(); + final BlockType blockType = state.getBlockType(); + TextComponent blockName = TextComponent.of(blockType.getName(), TextColor.LIGHT_PURPLE); + TextComponent toolTip; + if (separateStates && state != blockType.getDefaultState()) { + toolTip = TextComponent.of(state.getAsString(), TextColor.GRAY); + blockName = blockName.append(TextComponent.of("*", TextColor.LIGHT_PURPLE)); + } else { + toolTip = TextComponent.of(blockType.getId(), TextColor.GRAY); + } + blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip)); + line.append(blockName); + + return line.build(); + } + + @Override + public int getComponentsSize() { + return distribution.size(); + } + + @Override + public Component create(int page) throws InvalidComponentException { + super.getContents().append(TextComponent.of("Total Block Count: " + totalBlocks, TextColor.GRAY)) + .append(TextComponent.newline()); + return super.create(page); + } + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 76e5d441e..9d3765943 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -523,7 +523,8 @@ public class UtilityCommands { int page, @Arg(desc = "The command to retrieve help for", def = "", variable = true) List command) throws WorldEditException { - PrintCommandHelp.help(command, page, listSubCommands, we, actor); + PrintCommandHelp.help(command, page, listSubCommands, + we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "//help"); } } 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 02ab382a4..25329885a 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 @@ -164,6 +164,7 @@ public class WorldEditCommands { int page, @Arg(desc = "The command to retrieve help for", def = "", variable = true) List command) throws WorldEditException { - PrintCommandHelp.help(command, page, listSubCommands, we, actor); + PrintCommandHelp.help(command, page, listSubCommands, + we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "/worldedit help"); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java index ad7dad226..dc3e97865 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/PrintCommandHelp.java @@ -67,11 +67,11 @@ public class PrintCommandHelp { return mapping.orElse(null); } - public static void help(List commandPath, int page, boolean listSubCommands, WorldEdit we, Actor actor) throws InvalidComponentException { - CommandManager manager = we.getPlatformManager().getPlatformCommandManager().getCommandManager(); + public static void help(List commandPath, int page, boolean listSubCommands, + CommandManager manager, Actor actor, String helpRootCommand) throws InvalidComponentException { if (commandPath.isEmpty()) { - printCommands(page, manager.getAllCommands(), actor, ImmutableList.of()); + printCommands(page, manager.getAllCommands(), actor, ImmutableList.of(), helpRootCommand); return; } @@ -93,7 +93,7 @@ public class PrintCommandHelp { toCommandString(visited), subCommand)); // full help for single command CommandUsageBox box = new CommandUsageBox(visited, visited.stream() - .map(Command::getName).collect(Collectors.joining(" "))); + .map(Command::getName).collect(Collectors.joining(" ")), helpRootCommand); actor.print(box.create()); return; } @@ -105,7 +105,7 @@ public class PrintCommandHelp { actor.printError(String.format("The sub-command '%s' under '%s' could not be found.", subCommand, toCommandString(visited))); // list subcommands for currentCommand - printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited); + printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited, helpRootCommand); return; } } @@ -114,10 +114,10 @@ public class PrintCommandHelp { if (subCommands.isEmpty() || !listSubCommands) { // Create the message - CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited)); + CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited), helpRootCommand); actor.print(box.create()); } else { - printCommands(page, subCommands.values().stream(), actor, visited); + printCommands(page, subCommands.values().stream(), actor, visited, helpRootCommand); } } @@ -126,7 +126,7 @@ public class PrintCommandHelp { } private static void printCommands(int page, Stream commandStream, Actor actor, - List commandList) throws InvalidComponentException { + List commandList, String helpRootCommand) throws InvalidComponentException { // Get a list of aliases List commands = commandStream .sorted(byCleanName()) @@ -135,7 +135,8 @@ public class PrintCommandHelp { String used = commandList.isEmpty() ? null : toCommandString(commandList); CommandListBox box = new CommandListBox( (used == null ? "Help" : "Subcommands: " + used), - "//help -s -p %page%" + (used == null ? "" : " " + used)); + helpRootCommand + " -s -p %page%" + (used == null ? "" : " " + used), + helpRootCommand); if (!actor.isPlayer()) { box.formatForConsole(); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java deleted file mode 100644 index 797557a52..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/BlockDistributionResult.java +++ /dev/null @@ -1,90 +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 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.util.formatting.component; - -import com.google.common.base.Strings; -import com.sk89q.worldedit.util.Countable; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; -import com.sk89q.worldedit.util.formatting.text.format.TextColor; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockType; - -import java.util.List; - -public class BlockDistributionResult extends PaginationBox { - - private final List> distribution; - private final int totalBlocks; - private final boolean separateStates; - - public BlockDistributionResult(List> distribution, boolean separateStates) { - super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : "")); - this.distribution = distribution; - // note: doing things like region.getArea is inaccurate for non-cuboids. - this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum(); - this.separateStates = separateStates; - setComponentsPerPage(7); - } - - @Override - public Component getComponent(int number) { - Countable c = distribution.get(number); - TextComponent.Builder line = TextComponent.builder(); - - final int count = c.getAmount(); - - final double perc = count / (double) totalBlocks * 100; - final int maxDigits = (int) (Math.log10(totalBlocks) + 1); - final int curDigits = (int) (Math.log10(count) + 1); - line.append(String.format("%s%.3f%% ", perc < 10 ? " " : "", perc), TextColor.GOLD); - final int space = maxDigits - curDigits; - String pad = Strings.repeat(" ", space == 0 ? 2 : 2 * space + 1); - line.append(String.format("%s%s", count, pad), TextColor.YELLOW); - - final BlockState state = c.getID(); - final BlockType blockType = state.getBlockType(); - TextComponent blockName = TextComponent.of(blockType.getName(), TextColor.LIGHT_PURPLE); - TextComponent toolTip; - if (separateStates && state != blockType.getDefaultState()) { - toolTip = TextComponent.of(state.getAsString(), TextColor.GRAY); - blockName = blockName.append(TextComponent.of("*", TextColor.LIGHT_PURPLE)); - } else { - toolTip = TextComponent.of(blockType.getId(), TextColor.GRAY); - } - blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip)); - line.append(blockName); - - return line.build(); - } - - @Override - public int getComponentsSize() { - return distribution.size(); - } - - @Override - public Component create(int page) throws InvalidComponentException { - super.getContents().append(TextComponent.of("Total Block Count: " + totalBlocks, TextColor.GRAY)) - .append(TextComponent.newline()); - return super.create(page); - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java index fd579c6fb..2efc8b7b3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandListBox.java @@ -32,14 +32,16 @@ public class CommandListBox extends PaginationBox { private List commands = Lists.newArrayList(); private boolean hideHelp; + private String helpCommand; /** * Create a new box. * * @param title the title */ - public CommandListBox(String title, String pageCommand) { + public CommandListBox(String title, String pageCommand, String helpCommand) { super(title, pageCommand); + this.helpCommand = helpCommand; } @Override @@ -72,7 +74,7 @@ public class CommandListBox extends PaginationBox { this.hideHelp = hideHelp; } - private static class CommandEntry { + private class CommandEntry { private final String alias; private final Component description; private final String insertion; @@ -87,7 +89,7 @@ public class CommandListBox extends PaginationBox { TextComponentProducer line = new TextComponentProducer(); if (!hideHelp) { line.append(SubtleFormat.wrap("? ") - .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//help " + insertion)) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, CommandListBox.this.helpCommand + " " + insertion)) .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help")))); } TextComponent command = TextComponent.of(alias, TextColor.GOLD); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index e8abe0e38..579bd44a9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -45,9 +45,10 @@ public class CommandUsageBox extends TextComponentProducer { * * @param commands the commands to describe * @param commandString the commands that were used, such as "/we" or "/brush sphere" + * @param helpRootCommand the command used to get subcommand help */ - public CommandUsageBox(List commands, String commandString) throws InvalidComponentException { - this(commands, commandString, null); + public CommandUsageBox(List commands, String commandString, String helpRootCommand) throws InvalidComponentException { + this(commands, commandString, helpRootCommand, null); } /** @@ -55,15 +56,18 @@ public class CommandUsageBox extends TextComponentProducer { * * @param commands the commands to describe * @param commandString the commands that were used, such as "/we" or "/brush sphere" + * @param helpRootCommand the command used to get subcommand help * @param parameters list of parameters to use */ - public CommandUsageBox(List commands, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException { + public CommandUsageBox(List commands, String commandString, String helpRootCommand, + @Nullable CommandParameters parameters) throws InvalidComponentException { checkNotNull(commands); checkNotNull(commandString); - attachCommandUsage(commands, commandString); + checkNotNull(helpRootCommand); + attachCommandUsage(commands, commandString, helpRootCommand); } - private void attachCommandUsage(List commands, String commandString) { + private void attachCommandUsage(List commands, String commandString, String helpRootCommand) { TextComponentProducer boxContent = new TextComponentProducer() .append(HelpGenerator.create(commands).getFullHelp()); if (getSubCommands(Iterables.getLast(commands)).size() > 0) { @@ -73,7 +77,7 @@ public class CommandUsageBox extends TextComponentProducer { .append(TextComponent.builder("List Subcommands") .color(ColorConfig.getMainText()) .decoration(TextDecoration.ITALIC, true) - .clickEvent(ClickEvent.runCommand("//help -s " + commandString)) + .clickEvent(ClickEvent.runCommand(helpRootCommand + " -s " + commandString)) .hoverEvent(HoverEvent.showText(TextComponent.of("List all subcommands of this command"))) .build()) .build()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java deleted file mode 100644 index ae052d137..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/SchematicPaginationBox.java +++ /dev/null @@ -1,75 +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 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.util.formatting.component; - -import com.google.common.collect.Multimap; -import com.google.common.io.Files; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; -import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; -import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; -import com.sk89q.worldedit.util.formatting.text.format.TextColor; - -import java.io.File; -import java.util.regex.Pattern; - -import static com.google.common.base.Preconditions.checkArgument; - -public class SchematicPaginationBox extends PaginationBox { - private final String prefix; - private final File[] files; - - public SchematicPaginationBox(String rootDir, File[] files, String pageCommand) { - super("Available schematics", pageCommand); - this.prefix = rootDir == null ? "" : rootDir; - this.files = files; - } - - @Override - public Component getComponent(int number) { - checkArgument(number < files.length && number >= 0); - File file = files[number]; - Multimap exts = ClipboardFormats.getFileExtensionMap(); - String format = exts.get(Files.getFileExtension(file.getName())) - .stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown"); - boolean inRoot = file.getParentFile().getName().equals(prefix); - - String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1]; - - return TextComponent.builder() - .content("") - .append(TextComponent.of("[L]") - .color(TextColor.GOLD) - .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load " + path)) - .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load")))) - .append(TextComponent.space()) - .append(TextComponent.of(path) - .color(TextColor.DARK_GREEN) - .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format)))) - .build(); - } - - @Override - public int getComponentsSize() { - return files.length; - } -} From 0f420f02ff112b5a4d05a4a22d8358b079acfc8c Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 27 Jul 2019 11:45:09 -0400 Subject: [PATCH 291/366] Fix some load-order issues probably. Edge cases might still exist around plugins which use WE for initial world-gen, or in general plugins that try to access the platform before it's ready. --- .../worldedit/bukkit/WorldEditPlugin.java | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) 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 a81aab7c5..e4fb3ea8c 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 @@ -96,7 +96,6 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { private static final Logger log = LoggerFactory.getLogger(WorldEditPlugin.class); public static final String CUI_PLUGIN_CHANNEL = "worldedit:cui"; private static WorldEditPlugin INSTANCE; - private static WorldInitListener worldInitListener = null; private BukkitImplAdapter bukkitAdapter; private BukkitServerInterface server; @@ -139,22 +138,19 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { getServer().getPluginManager().registerEvents(new AsyncTabCompleteListener(), this); } - // register this so we can load world-dependent data right as the first world is loading - if (worldInitListener != null) { + initializeRegistries(); // this creates the objects matching Bukkit's enums - but doesn't fill them with data yet + if (Bukkit.getWorlds().isEmpty()) { + setupPreWorldData(); + // register this so we can load world-dependent data right as the first world is loading + getServer().getPluginManager().registerEvents(new WorldInitListener(), this); + } else { getLogger().warning("Server reload detected. This may cause various issues with WorldEdit and dependent plugins."); try { - // these don't stick around between reload - loadAdapter(); - loadConfig(); - WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + setupPreWorldData(); + // since worlds are loaded already, we can do this now + setupWorldData(); } catch (Throwable ignored) { } - } else { - getServer().getPluginManager().registerEvents((worldInitListener = new WorldInitListener()), this); - loadAdapter(); // Need an adapter to work with special blocks with NBT data - setupRegistries(); - WorldEdit.getInstance().loadMappings(); - loadConfig(); // Load configuration } // Enable metrics @@ -162,12 +158,19 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { PaperLib.suggestPaper(this); } + private void setupPreWorldData() { + loadAdapter(); + loadConfig(); + WorldEdit.getInstance().loadMappings(); + } + private void setupWorldData() { - setupTags(); + setupTags(); // datapacks aren't loaded until just before the world is, and bukkit has no event for this + // so the earliest we can do this is in WorldInit WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); } - private void setupRegistries() { + private void initializeRegistries() { // Biome for (Biome biome : Biome.values()) { String lowerCaseBiomeName = biome.name().toLowerCase(Locale.ROOT); @@ -487,9 +490,9 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { if (!event.isCommand()) return; String buffer = event.getBuffer(); - final String[] parts = buffer.split(" "); - if (parts.length < 1) return; - final String label = parts[0]; + int firstSpace = buffer.indexOf(' '); + if (firstSpace < 0) return; + final String label = buffer.substring(0, firstSpace); final Optional command = WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().getCommand(label); if (!command.isPresent()) return; From 3a5170a0e80736bf7d966b3c142509195dabe3b4 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 27 Jul 2019 18:12:18 -0700 Subject: [PATCH 292/366] Potenially fix quoted string completion --- .../platform/PlatformCommandManager.java | 2 +- .../internal/command/CommandArgParser.java | 10 +++++--- .../internal/command/CommandUtil.java | 5 +++- .../command/CommandArgParserTest.java | 23 ++++++++++++------- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 3086613ec..673bb2a17 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -431,7 +431,7 @@ public final class PlatformCommandManager { } private Stream parseArgs(String input) { - return new CommandArgParser(CommandArgParser.spaceSplit(input.substring(1))).parseArgs(); + return CommandArgParser.forArgString(input.substring(1)).parseArgs(); } @Subscribe diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java index 156563bbb..07e878068 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandArgParser.java @@ -31,6 +31,10 @@ import java.util.stream.Stream; public class CommandArgParser { + public static CommandArgParser forArgString(String argString) { + return new CommandArgParser(spaceSplit(argString)); + } + public static ImmutableList spaceSplit(String string) { ImmutableList.Builder result = ImmutableList.builder(); int index = 0; @@ -79,14 +83,14 @@ public class CommandArgParser { if (strPart.endsWith("\"") && strPart.length() > 1) { currentArg.add(Substring.wrap( strPart.substring(1, strPart.length() - 1), - part.getStart(), part.getEnd() + part.getStart() + 1, part.getEnd() - 1 )); finishArg(); } else { state = State.QUOTE; currentArg.add(Substring.wrap( strPart.substring(1), - part.getStart(), part.getEnd() + part.getStart() + 1, part.getEnd() )); } } else { @@ -100,7 +104,7 @@ public class CommandArgParser { state = State.NORMAL; currentArg.add(Substring.wrap( part.getSubstring().substring(0, part.getSubstring().length() - 1), - part.getStart(), part.getEnd() + part.getStart(), part.getEnd() - 1 )); finishArg(); } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java index b98236090..6dbb89648 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.internal.command; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.google.common.collect.Iterators; import com.sk89q.worldedit.extension.platform.PlatformCommandManager; import com.sk89q.worldedit.internal.util.Substring; import com.sk89q.worldedit.util.formatting.text.Component; @@ -65,7 +66,9 @@ public class CommandUtil { * Fix {@code suggestions} to replace the last space-separated word in {@code arguments}. */ public static List fixSuggestions(String arguments, List suggestions) { - Substring lastArg = Iterables.getLast(CommandArgParser.spaceSplit(arguments)); + Substring lastArg = Iterables.getLast( + CommandArgParser.spaceSplit(arguments) + ); return suggestions.stream() .map(suggestion -> CommandUtil.suggestLast(lastArg, suggestion)) .filter(Optional::isPresent) diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java index c696bdabb..632e1219b 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/command/CommandArgParserTest.java @@ -23,29 +23,36 @@ import com.google.common.collect.ImmutableList; import com.sk89q.worldedit.internal.util.Substring; import org.junit.jupiter.api.Test; -import static com.sk89q.worldedit.internal.command.CommandArgParser.spaceSplit; +import java.util.List; +import java.util.stream.Collectors; + import static org.junit.jupiter.api.Assertions.assertEquals; -public class CommandArgParserTest { +class CommandArgParserTest { + + private static List argParse(String s) { + return CommandArgParser.forArgString(s).parseArgs().collect(Collectors.toList()); + } + @Test - public void testSpaceSplit() { + void testArgumentParsing() { assertEquals(ImmutableList.of( Substring.wrap("", 0, 0) - ), spaceSplit("")); + ), argParse("")); assertEquals(ImmutableList.of( Substring.wrap("ab", 0, 2) - ), spaceSplit("ab")); + ), argParse("ab")); assertEquals(ImmutableList.of( Substring.wrap("", 0, 0), Substring.wrap("", 1, 1) - ), spaceSplit(" ")); + ), argParse(" ")); assertEquals(ImmutableList.of( Substring.wrap("a", 0, 1), Substring.wrap("", 2, 2) - ), spaceSplit("a ")); + ), argParse("a ")); assertEquals(ImmutableList.of( Substring.wrap("a", 0, 1), Substring.wrap("b", 2, 3) - ), spaceSplit("a b")); + ), argParse("a b")); } } From 76b608f90b2afd4e4cf6c0497ef86731f6bfc0e4 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 27 Jul 2019 23:31:38 -0700 Subject: [PATCH 293/366] Fix suggestions on Bukkit for good --- .../sk89q/worldedit/bukkit/WorldEditPlugin.java | 4 ++-- .../worldedit/internal/command/CommandUtil.java | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) 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 e4fb3ea8c..69e53ee5b 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 @@ -335,7 +335,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // code of WorldEdit expects it String[] split = new String[args.length + 1]; System.arraycopy(args, 0, split, 1, args.length); - split[0] = "/" + cmd.getName(); + split[0] = "/" + commandLabel; CommandEvent event = new CommandEvent(wrapCommandSender(sender), Joiner.on(" ").join(split)); getWorldEdit().getEventBus().post(event); @@ -349,7 +349,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { // code of WorldEdit expects it String[] split = new String[args.length + 1]; System.arraycopy(args, 0, split, 1, args.length); - split[0] = "/" + cmd.getName(); + split[0] = "/" + commandLabel; String arguments = Joiner.on(" ").join(split); CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), arguments); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java index 6dbb89648..b259435a1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.internal.command; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; -import com.google.common.collect.Iterators; import com.sk89q.worldedit.extension.platform.PlatformCommandManager; import com.sk89q.worldedit.internal.util.Substring; import com.sk89q.worldedit.util.formatting.text.Component; @@ -70,18 +69,29 @@ public class CommandUtil { CommandArgParser.spaceSplit(arguments) ); return suggestions.stream() + // Re-map suggestions to only operate on the last non-quoted word + .map(CommandUtil::onlyOnLastQuotedWord) .map(suggestion -> CommandUtil.suggestLast(lastArg, suggestion)) .filter(Optional::isPresent) .map(Optional::get) .collect(toList()); } + private static Substring onlyOnLastQuotedWord(Substring suggestion) { + String substr = suggestion.getSubstring(); + int sp = substr.lastIndexOf(' '); + if (sp < 0) { + return suggestion; + } + return Substring.wrap(substr.substring(sp + 1), suggestion.getStart() + sp + 1, suggestion.getEnd()); + } + /** * Given the last word of a command, mutate the suggestion to replace the last word, if * possible. */ private static Optional suggestLast(Substring last, Substring suggestion) { - if (suggestion.getStart() == last.getEnd()) { + if (suggestion.getStart() == last.getEnd() && !last.getSubstring().equals("\"")) { // this suggestion is for the next argument. if (last.getSubstring().isEmpty()) { return Optional.of(suggestion.getSubstring()); From 50cea37439ed048f0a28e14535fb855987aef027 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 27 Jul 2019 23:49:11 -0700 Subject: [PATCH 294/366] Fix other minor suggestion bugs --- .../com/sk89q/worldedit/command/util/SuggestionHelper.java | 2 +- .../main/java/com/sk89q/worldedit/fabric/CommandWrapper.java | 3 ++- .../main/java/com/sk89q/worldedit/forge/CommandWrapper.java | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java index e0014ee56..3a41711b6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java @@ -51,7 +51,7 @@ public final class SuggestionHelper { if (tag.isEmpty() || tag.equals("#")) { return Stream.of("##", "##*"); } - if (tag.startsWith("#")) { + if (tag.startsWith("##")) { if (tag.equals("##")) { return Stream.concat(Stream.of("##*"), getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(2)).map(s -> "##" + s)); } else if (tag.equals("##*") && allowRandom) { diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/CommandWrapper.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/CommandWrapper.java index 8efa5ce97..462975acb 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/CommandWrapper.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/CommandWrapper.java @@ -111,7 +111,8 @@ public final class CommandWrapper { // Ensure there is a space! if (suggestion.getStart() == suggestion.getEnd() && suggestion.getEnd() == builder.getInput().length() - && !builder.getInput().endsWith(" ")) { + && !builder.getInput().endsWith(" ") + && !builder.getInput().endsWith("\"")) { suggestionText = " " + suggestionText; } result.add(new Suggestion( diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java index 05d4fe5ad..0cf62fb4b 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/CommandWrapper.java @@ -103,7 +103,8 @@ public final class CommandWrapper { // Ensure there is a space! if (suggestion.getStart() == suggestion.getEnd() && suggestion.getEnd() == builder.getInput().length() - && !builder.getInput().endsWith(" ")) { + && !builder.getInput().endsWith(" ") + && !builder.getInput().endsWith("\"")) { suggestionText = " " + suggestionText; } result.add(new Suggestion( From c93e5ccfdfd100c20836c66ce7f280beaf5d0e6f Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 28 Jul 2019 10:02:47 -0400 Subject: [PATCH 295/366] Don't suggest ##* for masks. --- .../com/sk89q/worldedit/command/util/SuggestionHelper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java index 3a41711b6..ed5e3aacb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/SuggestionHelper.java @@ -49,11 +49,12 @@ public final class SuggestionHelper { public static Stream getBlockCategorySuggestions(String tag, boolean allowRandom) { if (tag.isEmpty() || tag.equals("#")) { - return Stream.of("##", "##*"); + return allowRandom ? Stream.of("##", "##*") : Stream.of("##"); } if (tag.startsWith("##")) { if (tag.equals("##")) { - return Stream.concat(Stream.of("##*"), getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(2)).map(s -> "##" + s)); + return Stream.concat(allowRandom ? Stream.of("##*") : Stream.empty(), + getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(2)).map(s -> "##" + s)); } else if (tag.equals("##*") && allowRandom) { return getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(3)).map(s -> "##*" + s); } else { From f4c238c3daa49aab455f3786e3f7427d82ec449f Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 28 Jul 2019 10:21:29 -0400 Subject: [PATCH 296/366] Load chunks when setting biomes too. --- .../worldedit/extent/world/ChunkLoadingExtent.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java index de5ae4378..a2ea51ed4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/ChunkLoadingExtent.java @@ -24,8 +24,10 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; /** @@ -67,4 +69,12 @@ public class ChunkLoadingExtent extends AbstractDelegateExtent { } return super.setBlock(location, block); } + + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + if (enabled) { + world.checkLoadedChunk(position.toBlockVector3()); + } + return super.setBiome(position, biome); + } } From 6631b6bdf0638b674b0f0dabad4eb77c0510e5df Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 28 Jul 2019 18:20:00 -0400 Subject: [PATCH 297/366] Make BlockStateHolder extend Pattern. Removes the need for wrapping them in BlockPattern. --- .../java/com/sk89q/worldedit/EditSession.java | 28 ++++++++----------- .../worldedit/command/BrushCommands.java | 4 +-- .../sk89q/worldedit/command/ToolCommands.java | 10 +++---- .../worldedit/command/tool/BlockReplacer.java | 5 ++-- .../command/tool/brush/CylinderBrush.java | 3 +- .../tool/brush/HollowCylinderBrush.java | 3 +- .../command/tool/brush/HollowSphereBrush.java | 3 +- .../command/tool/brush/SphereBrush.java | 3 +- .../pattern/BlockCategoryPatternParser.java | 5 ++-- .../pattern/RandomStatePatternParser.java | 3 +- .../pattern/SingleBlockPatternParser.java | 3 +- .../function/generator/FloraGenerator.java | 13 ++++----- .../generator/GardenPatchGenerator.java | 5 ++-- .../function/pattern/BlockPattern.java | 3 ++ .../worldedit/world/block/BaseBlock.java | 6 ++++ .../worldedit/world/block/BlockState.java | 6 ++++ .../world/block/BlockStateHolder.java | 9 +++++- 17 files changed, 59 insertions(+), 53 deletions(-) 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 8501ba917..07f4fd795 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -62,7 +62,6 @@ import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.WaterloggedRemover; import com.sk89q.worldedit.function.util.RegionOffset; @@ -820,7 +819,7 @@ public class EditSession implements Extent, AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public > int fillXZ(BlockVector3 origin, B block, double radius, int depth, boolean recursive) throws MaxChangedBlocksException { - return fillXZ(origin, new BlockPattern(block), radius, depth, recursive); + return fillXZ(origin, (Pattern) block, radius, depth, recursive); } /** @@ -885,8 +884,7 @@ public class EditSession implements Extent, AutoCloseable { getWorld(), // Causes clamping of Y range position.add(-apothem + 1, 0, -apothem + 1), position.add(apothem - 1, height - 1, apothem - 1)); - Pattern pattern = new BlockPattern(BlockTypes.AIR.getDefaultState()); - return setBlocks(region, pattern); + return setBlocks(region, BlockTypes.AIR.getDefaultState()); } /** @@ -907,8 +905,7 @@ public class EditSession implements Extent, AutoCloseable { getWorld(), // Causes clamping of Y range position.add(-apothem + 1, 0, -apothem + 1), position.add(apothem - 1, -height + 1, apothem - 1)); - Pattern pattern = new BlockPattern(BlockTypes.AIR.getDefaultState()); - return setBlocks(region, pattern); + return setBlocks(region, BlockTypes.AIR.getDefaultState()); } /** @@ -929,8 +926,7 @@ public class EditSession implements Extent, AutoCloseable { getWorld(), // Causes clamping of Y range position.add(adjustment.multiply(-1)), position.add(adjustment)); - Pattern pattern = new BlockPattern(BlockTypes.AIR.getDefaultState()); - return replaceBlocks(region, mask, pattern); + return replaceBlocks(region, mask, BlockTypes.AIR.getDefaultState()); } /** @@ -942,7 +938,7 @@ public class EditSession implements Extent, AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public > int setBlocks(Region region, B block) throws MaxChangedBlocksException { - return setBlocks(region, new BlockPattern(block)); + return setBlocks(region, (Pattern) block); } /** @@ -974,7 +970,7 @@ public class EditSession implements Extent, AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public > int replaceBlocks(Region region, Set filter, B replacement) throws MaxChangedBlocksException { - return replaceBlocks(region, filter, new BlockPattern(replacement)); + return replaceBlocks(region, filter, (Pattern) replacement); } /** @@ -1046,7 +1042,7 @@ public class EditSession implements Extent, AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public > int makeCuboidFaces(Region region, B block) throws MaxChangedBlocksException { - return makeCuboidFaces(region, new BlockPattern(block)); + return makeCuboidFaces(region, block); } /** @@ -1098,7 +1094,7 @@ public class EditSession implements Extent, AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public > int makeCuboidWalls(Region region, B block) throws MaxChangedBlocksException { - return makeCuboidWalls(region, new BlockPattern(block)); + return makeCuboidWalls(region, (Pattern) block); } /** @@ -1165,7 +1161,7 @@ public class EditSession implements Extent, AutoCloseable { public > int overlayCuboidBlocks(Region region, B block) throws MaxChangedBlocksException { checkNotNull(block); - return overlayCuboidBlocks(region, new BlockPattern(block)); + return overlayCuboidBlocks(region, (Pattern) block); } /** @@ -1255,7 +1251,7 @@ public class EditSession implements Extent, AutoCloseable { // Remove the original blocks Pattern pattern = replacement != null ? replacement : - new BlockPattern(BlockTypes.AIR.getDefaultState()); + BlockTypes.AIR.getDefaultState(); BlockReplace remove = new BlockReplace(this, pattern); // Copy to a buffer so we don't destroy our original before we can copy all the blocks from it @@ -1334,7 +1330,7 @@ public class EditSession implements Extent, AutoCloseable { if (waterlogged) { replace = new BlockReplace(this, new WaterloggedRemover(this)); } else { - replace = new BlockReplace(this, new BlockPattern(BlockTypes.AIR.getDefaultState())); + replace = new BlockReplace(this, BlockTypes.AIR.getDefaultState()); } RecursiveVisitor visitor = new RecursiveVisitor(mask, replace); @@ -1376,7 +1372,7 @@ public class EditSession implements Extent, AutoCloseable { blockMask ); - BlockReplace replace = new BlockReplace(this, new BlockPattern(fluid.getDefaultState())); + BlockReplace replace = new BlockReplace(this, fluid.getDefaultState()); NonRisingVisitor visitor = new NonRisingVisitor(mask, replace); // Around the origin in a 3x3 block 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 a5b6290d6..25f198e92 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 @@ -47,7 +47,6 @@ import com.sk89q.worldedit.function.factory.Paint; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.factory.RegionFactory; @@ -207,8 +206,7 @@ public class BrushCommands { worldEdit.checkMaxBrushRadius(radius); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); - Pattern fill = new BlockPattern(BlockTypes.AIR.getDefaultState()); - tool.setFill(fill); + tool.setFill(BlockTypes.AIR.getDefaultState()); tool.setSize(radius); tool.setMask(new BlockTypeMask(new RequestExtent(), BlockTypes.FIRE)); tool.setBrush(new SphereBrush(), "worldedit.brush.ex"); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 6bbd2d853..5c8de085c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -37,10 +37,10 @@ import com.sk89q.worldedit.command.tool.TreePlanter; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.item.ItemType; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; @@ -209,11 +209,11 @@ public class ToolCommands { player.print("Long-range building tool bound to " + itemStack.getType().getName() + "."); String primaryName = "pattern"; String secondaryName = "pattern"; - if (primary instanceof BlockPattern) { - primaryName = ((BlockPattern) primary).getBlock().getBlockType().getName(); + if (primary instanceof BlockStateHolder) { + primaryName = ((BlockStateHolder) primary).getBlockType().getName(); } - if (secondary instanceof BlockPattern) { - secondaryName = ((BlockPattern) secondary).getBlock().getBlockType().getName(); + if (secondary instanceof BlockStateHolder) { + secondaryName = ((BlockStateHolder) secondary).getBlockType().getName(); } player.print("Left-click set to " + primaryName + "; right-click set to " + secondaryName + "."); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java index b48c8adca..65d3f0ea0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/BlockReplacer.java @@ -27,7 +27,6 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extent.inventory.BlockBag; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Location; @@ -57,7 +56,7 @@ public class BlockReplacer implements DoubleActionBlockTool { try { editSession.disableBuffering(); BlockVector3 position = clicked.toVector().toBlockPoint(); - editSession.setBlock(position, pattern.apply(position)); + editSession.setBlock(position, pattern); } catch (MaxChangedBlocksException ignored) { } finally { session.remember(editSession); @@ -77,7 +76,7 @@ public class BlockReplacer implements DoubleActionBlockTool { BaseBlock targetBlock = player.getWorld().getFullBlock(clicked.toVector().toBlockPoint()); if (targetBlock != null) { - pattern = new BlockPattern(targetBlock); + pattern = targetBlock; player.print("Replacer tool switched to: " + targetBlock.getBlockType().getName()); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java index 12a663ed3..1b1ddcb6f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/CylinderBrush.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.command.tool.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockTypes; @@ -37,7 +36,7 @@ public class CylinderBrush implements Brush { @Override public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { if (pattern == null) { - pattern = new BlockPattern(BlockTypes.COBBLESTONE.getDefaultState()); + pattern = BlockTypes.COBBLESTONE.getDefaultState(); } editSession.makeCylinder(position, pattern, size, size, height, true); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java index dbf959e1b..4cbef5503 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowCylinderBrush.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.command.tool.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockTypes; @@ -37,7 +36,7 @@ public class HollowCylinderBrush implements Brush { @Override public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { if (pattern == null) { - pattern = new BlockPattern(BlockTypes.COBBLESTONE.getDefaultState()); + pattern = BlockTypes.COBBLESTONE.getDefaultState(); } editSession.makeCylinder(position, pattern, size, size, height, false); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java index 0e89b3c16..c4170d00e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/HollowSphereBrush.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.command.tool.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockTypes; @@ -31,7 +30,7 @@ public class HollowSphereBrush implements Brush { @Override public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { if (pattern == null) { - pattern = new BlockPattern(BlockTypes.COBBLESTONE.getDefaultState()); + pattern = BlockTypes.COBBLESTONE.getDefaultState(); } editSession.makeSphere(position, pattern, size, size, size, false); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java index d8028f2ae..03b50a7e9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/brush/SphereBrush.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.command.tool.brush; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockTypes; @@ -31,7 +30,7 @@ public class SphereBrush implements Brush { @Override public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException { if (pattern == null) { - pattern = new BlockPattern(BlockTypes.COBBLESTONE.getDefaultState()); + pattern = BlockTypes.COBBLESTONE.getDefaultState(); } editSession.makeSphere(position, pattern, size, size, size, true); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java index 3260fa438..4ff9cd913 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/BlockCategoryPatternParser.java @@ -23,7 +23,6 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.util.SuggestionHelper; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.internal.registry.InputParser; @@ -70,10 +69,10 @@ public class BlockCategoryPatternParser extends InputParser { if (anyState) { blocks.stream().flatMap(blockType -> blockType.getAllStates().stream()).forEach(state -> - randomPattern.add(new BlockPattern(state), 1.0)); + randomPattern.add(state, 1.0)); } else { for (BlockType blockType : blocks) { - randomPattern.add(new BlockPattern(blockType.getDefaultState()), 1.0); + randomPattern.add(blockType.getDefaultState(), 1.0); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java index 3b6dc5c1f..d8f27b08c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/RandomStatePatternParser.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.extension.factory.parser.pattern; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.RandomStatePattern; import com.sk89q.worldedit.internal.registry.InputParser; @@ -60,7 +59,7 @@ public class RandomStatePatternParser extends InputParser { context.setPreferringWildcard(wasFuzzy); if (block.getStates().size() == block.getBlockType().getPropertyMap().size()) { // they requested random with *, but didn't leave any states empty - simplify - return new BlockPattern(block); + return block; } else if (block.toImmutableState() instanceof FuzzyBlockState) { return new RandomStatePattern((FuzzyBlockState) block.toImmutableState()); } else { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java index 30f844611..2565b5d70 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/pattern/SingleBlockPatternParser.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.extension.factory.parser.pattern; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.registry.InputParser; @@ -41,7 +40,7 @@ public class SingleBlockPatternParser extends InputParser { @Override public Pattern parseFromInput(String input, ParserContext context) throws InputParseException { - return new BlockPattern(worldEdit.getBlockFactory().parseFromInput(input, context)); + return worldEdit.getBlockFactory().parseFromInput(input, context); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java index 039d1a7fd..d133993cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FloraGenerator.java @@ -22,7 +22,6 @@ package com.sk89q.worldedit.function.generator; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.function.RegionFunction; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.RandomPattern; import com.sk89q.worldedit.math.BlockVector3; @@ -83,9 +82,9 @@ public class FloraGenerator implements RegionFunction { */ public static Pattern getDesertPattern() { RandomPattern pattern = new RandomPattern(); - pattern.add(new BlockPattern(BlockTypes.DEAD_BUSH.getDefaultState()), 30); - pattern.add(new BlockPattern(BlockTypes.CACTUS.getDefaultState()), 20); - pattern.add(new BlockPattern(BlockTypes.AIR.getDefaultState()), 300); + pattern.add(BlockTypes.DEAD_BUSH.getDefaultState(), 30); + pattern.add(BlockTypes.CACTUS.getDefaultState(), 20); + pattern.add(BlockTypes.AIR.getDefaultState(), 300); return pattern; } @@ -96,9 +95,9 @@ public class FloraGenerator implements RegionFunction { */ public static Pattern getTemperatePattern() { RandomPattern pattern = new RandomPattern(); - pattern.add(new BlockPattern(BlockTypes.GRASS.getDefaultState()), 300); - pattern.add(new BlockPattern(BlockTypes.POPPY.getDefaultState()), 5); - pattern.add(new BlockPattern(BlockTypes.DANDELION.getDefaultState()), 5); + pattern.add(BlockTypes.GRASS.getDefaultState(), 300); + pattern.add(BlockTypes.POPPY.getDefaultState(), 5); + pattern.add(BlockTypes.DANDELION.getDefaultState(), 5); return pattern; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java index 0d31760af..5d1aa01c5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java @@ -23,7 +23,6 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.function.RegionFunction; -import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockState; @@ -187,7 +186,7 @@ public class GardenPatchGenerator implements RegionFunction { * @return a pumpkin pattern */ public static Pattern getPumpkinPattern() { - return new BlockPattern(BlockTypes.PUMPKIN.getDefaultState()); + return BlockTypes.PUMPKIN.getDefaultState(); } /** @@ -208,6 +207,6 @@ public class GardenPatchGenerator implements RegionFunction { * @return a melon pattern */ public static Pattern getMelonPattern() { - return new BlockPattern(BlockTypes.MELON.getDefaultState()); + return BlockTypes.MELON.getDefaultState(); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java index fa49f5108..a934bc17a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BlockPattern.java @@ -27,7 +27,10 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; /** * A pattern that returns the same {@link BaseBlock} each time. + * + * @deprecated all BlockStateHolders can be used directly as a pattern */ +@Deprecated public class BlockPattern extends AbstractPattern { private BaseBlock block; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index bc913f2d7..713a36eff 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -25,6 +25,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.TileEntityBlock; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import java.util.Map; @@ -166,6 +167,11 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { return this; } + @Override + public BaseBlock apply(BlockVector3 position) { + return this; + } + @Override public BaseBlock toBaseBlock(CompoundTag compoundTag) { if (compoundTag == null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index aeeae8210..c8c39cc78 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -28,6 +28,7 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.registry.BlockRegistry; @@ -207,6 +208,11 @@ public class BlockState implements BlockStateHolder { return this.emptyBaseBlock; } + @Override + public BaseBlock apply(BlockVector3 position) { + return this.emptyBaseBlock; + } + @Override public BaseBlock toBaseBlock(CompoundTag compoundTag) { if (compoundTag == null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java index 481ee1d63..d6ada3d74 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockStateHolder.java @@ -20,13 +20,15 @@ package com.sk89q.worldedit.world.block; import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; -public interface BlockStateHolder> { +public interface BlockStateHolder> extends Pattern { /** * Get the block type @@ -89,6 +91,11 @@ public interface BlockStateHolder> { */ BaseBlock toBaseBlock(CompoundTag compoundTag); + @Override + default BaseBlock apply(BlockVector3 position) { + return toBaseBlock(); + } + default String getAsString() { if (getStates().isEmpty()) { return this.getBlockType().getId(); From 9d9e3ea065fd3c45eaf6f3886a4951c3bb17587a Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 28 Jul 2019 22:50:42 -0400 Subject: [PATCH 298/366] Remove overrides. --- .../java/com/sk89q/worldedit/world/block/BaseBlock.java | 6 ------ .../java/com/sk89q/worldedit/world/block/BlockState.java | 6 ------ 2 files changed, 12 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java index 713a36eff..bc913f2d7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BaseBlock.java @@ -25,7 +25,6 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.TileEntityBlock; -import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import java.util.Map; @@ -167,11 +166,6 @@ public class BaseBlock implements BlockStateHolder, TileEntityBlock { return this; } - @Override - public BaseBlock apply(BlockVector3 position) { - return this; - } - @Override public BaseBlock toBaseBlock(CompoundTag compoundTag) { if (compoundTag == null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index c8c39cc78..aeeae8210 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -28,7 +28,6 @@ import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; -import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.registry.BlockRegistry; @@ -208,11 +207,6 @@ public class BlockState implements BlockStateHolder { return this.emptyBaseBlock; } - @Override - public BaseBlock apply(BlockVector3 position) { - return this.emptyBaseBlock; - } - @Override public BaseBlock toBaseBlock(CompoundTag compoundTag) { if (compoundTag == null) { From c5f46d15e1a35792366c04ef10b0d1bc82a081f1 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 29 Jul 2019 11:32:48 -0400 Subject: [PATCH 299/366] Switch build badge to TC. Also remove dead wiki link. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 93290bcf6..dbc907064 100644 --- a/README.md +++ b/README.md @@ -31,5 +31,5 @@ Links * [Discord](https://discord.gg/enginehub) * [IRC channel](https://webchat.esper.net/?join=sk89q) (#sk89q on irc.esper.net) * [Issue tracker](https://dev.enginehub.org/youtrack/issues/WORLDEDIT) -* [Continuous integration](http://builds.enginehub.org) [![Build Status](https://travis-ci.org/EngineHub/WorldEdit.svg?branch=master)](https://travis-ci.org/EngineHub/WorldEdit) -* [End-user documentation](https://worldedit.readthedocs.io/en/latest/) / [Older Wiki](http://wiki.sk89q.com/wiki/WorldEdit) +* [Continuous integration](http://builds.enginehub.org) [![Build Status](https://ci.enginehub.org/app/rest/builds/buildType:bt10,branch:master/statusIcon.svg)](http://ci.enginehub.org/viewType.html?buildTypeId=bt10&guest=1) +* [End-user documentation](https://worldedit.readthedocs.io/en/latest/) From afae2b0784c10c3c4e47f89b9fa6e07733470cd0 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 1 Aug 2019 20:15:34 -0400 Subject: [PATCH 300/366] Make TE tag optional for MCEdit schems too. And name our threads here too. --- .../java/com/sk89q/worldedit/WorldEdit.java | 3 ++- .../clipboard/io/MCEditSchematicReader.java | 6 +++-- .../worldedit/session/SessionManager.java | 9 ++++--- .../util/concurrency/EvenMoreExecutors.java | 26 ++++++++++++++++--- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index 7aec0298a..55e36892e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -105,7 +105,8 @@ public final class WorldEdit { private final PlatformManager platformManager = new PlatformManager(this); private final EditSessionFactory editSessionFactory = new EditSessionFactory.EditSessionFactoryImpl(eventBus); private final SessionManager sessions = new SessionManager(this); - private final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20));; + private final ListeningExecutorService executorService = MoreExecutors.listeningDecorator( + EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20, "WorldEdit Task Executor - %s")); private final Supervisor supervisor = new SimpleSupervisor(); private final BlockFactory blockFactory = new BlockFactory(this); 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 61110ea09..948bbe444 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 @@ -54,6 +54,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -177,7 +178,8 @@ public class MCEditSchematicReader extends NBTSchematicReader { } // Need to pull out tile entities - List tileEntities = requireTag(schematic, "TileEntities", ListTag.class).getValue(); + final ListTag tileEntityTag = getTag(schematic, "TileEntities", ListTag.class); + List tileEntities = tileEntityTag == null ? new ArrayList<>() : tileEntityTag.getValue(); Map> tileEntitiesMap = new HashMap<>(); Map blockStates = new HashMap<>(); @@ -245,7 +247,7 @@ public class MCEditSchematicReader extends NBTSchematicReader { byte data = blockData[index]; int combined = block << 8 | data; if (unknownBlocks.add(combined)) { - log.warn("Unknown block when pasting schematic: " + log.warn("Unknown block when loading schematic: " + block + ":" + data + ". Please report this issue."); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index 403d874c5..ef346d429 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.session; +import static com.google.common.base.Preconditions.checkNotNull; + import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; @@ -55,8 +57,6 @@ import java.util.TimerTask; import java.util.UUID; import java.util.concurrent.Callable; -import static com.google.common.base.Preconditions.checkNotNull; - /** * Session manager for WorldEdit. * @@ -68,11 +68,12 @@ public class SessionManager { public static int EXPIRATION_GRACE = 10 * 60 * 1000; private static final int FLUSH_PERIOD = 1000 * 30; - private static final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 5)); + private static final ListeningExecutorService executorService = MoreExecutors.listeningDecorator( + EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 5, "WorldEdit Session Saver - %s")); private static final Logger log = LoggerFactory.getLogger(SessionManager.class); private static boolean warnedInvalidTool; - private final Timer timer = new Timer(); + private final Timer timer = new Timer("WorldEdit Session Manager"); private final WorldEdit worldEdit; private final Map sessions = new HashMap<>(); private SessionStore store = new VoidStore(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/concurrency/EvenMoreExecutors.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/concurrency/EvenMoreExecutors.java index 5272039a1..1c40c9454 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/concurrency/EvenMoreExecutors.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/concurrency/EvenMoreExecutors.java @@ -19,8 +19,10 @@ package com.sk89q.worldedit.util.concurrency; -import java.util.concurrent.ArrayBlockingQueue; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -39,15 +41,33 @@ public final class EvenMoreExecutors { * * @param minThreads the minimum number of threads to have at a given time * @param maxThreads the maximum number of threads to have at a given time - * @param queueSize the size of the queue before new submissions are rejected + * @param queueSize the size of the queue before new submissions are rejected * @return the newly created thread pool */ public static ExecutorService newBoundedCachedThreadPool(int minThreads, int maxThreads, int queueSize) { + return newBoundedCachedThreadPool(minThreads, maxThreads, queueSize, null); + } + + /** + * Creates a thread pool that creates new threads as needed up to + * a maximum number of threads, but will reuse previously constructed + * threads when they are available. + * + * @param minThreads the minimum number of threads to have at a given time + * @param maxThreads the maximum number of threads to have at a given time + * @param queueSize the size of the queue before new submissions are rejected + * @param threadFormat thread name formatter + * @return the newly created thread pool + */ + public static ExecutorService newBoundedCachedThreadPool(int minThreads, int maxThreads, int queueSize, String threadFormat) { ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( minThreads, maxThreads, 60L, TimeUnit.SECONDS, - new ArrayBlockingQueue<>(queueSize)); + new LinkedBlockingDeque<>(queueSize)); threadPoolExecutor.allowCoreThreadTimeOut(true); + if (threadFormat != null) { + threadPoolExecutor.setThreadFactory(new ThreadFactoryBuilder().setNameFormat(threadFormat).build()); + } return threadPoolExecutor; } From 50341acab2df4af23017483747f07decf588fac1 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 1 Aug 2019 20:29:01 -0400 Subject: [PATCH 301/366] Fix travis. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 1c581a696..df4f54894 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +dist: trusty language: java notifications: email: false From 7d31ac6dea40e027776f2afb2e76c9f920d11819 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Fri, 2 Aug 2019 14:03:06 -0700 Subject: [PATCH 302/366] Update to Forge 28.0.34 for PlayerInteract fix --- worldedit-forge/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index 89ae7fc27..0d68dad28 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -13,7 +13,7 @@ applyShadowConfiguration() val minecraftVersion = "1.14.4" val mappingsMinecraftVersion = "1.14.3" -val forgeVersion = "28.0.16" +val forgeVersion = "28.0.34" configurations.all { resolutionStrategy { @@ -31,7 +31,7 @@ dependencies { configure { mappings(mapOf( "channel" to "snapshot", - "version" to "20190724-$mappingsMinecraftVersion" + "version" to "20190801-$mappingsMinecraftVersion" )) runs { From f848d3114fbf8d2b05dedc3ec0b1a7da66c29906 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Fri, 2 Aug 2019 15:47:29 -0700 Subject: [PATCH 303/366] Re-load internal state IDs when WORLD_EDITING cap is re-loaded --- .../extension/platform/Capability.java | 22 ++++++++- .../internal/block/BlockStateIdAccess.java | 45 +++++++------------ .../worldedit/world/block/BlockState.java | 20 ++------- 3 files changed, 41 insertions(+), 46 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java index e91c799bc..94f5115ec 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java @@ -19,6 +19,11 @@ package com.sk89q.worldedit.extension.platform; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BlockRegistry; + /** * A collection of capabilities that a {@link Platform} may support. */ @@ -73,7 +78,22 @@ public enum Capability { /** * The capability of a platform to perform modifications to a world. */ - WORLD_EDITING; + WORLD_EDITING { + @Override + void initialize(PlatformManager platformManager, Platform platform) { + BlockRegistry blockRegistry = platform.getRegistries().getBlockRegistry(); + for (BlockType type : BlockType.REGISTRY) { + for (BlockState state : type.getAllStates()) { + BlockStateIdAccess.register(state, blockRegistry.getInternalBlockStateId(state)); + } + } + } + + @Override + void unload(PlatformManager platformManager, Platform platform) { + BlockStateIdAccess.clear(); + } + }; void initialize(PlatformManager platformManager, Platform platform) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java index 172289c39..dcd8210b0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java @@ -19,57 +19,46 @@ package com.sk89q.worldedit.internal.block; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.sk89q.worldedit.world.block.BlockState; import javax.annotation.Nullable; import java.util.Arrays; +import java.util.Map; import java.util.OptionalInt; import static com.google.common.base.Preconditions.checkState; public final class BlockStateIdAccess { - private BlockStateIdAccess() { - } - - public interface Provider { - - OptionalInt getBlockStateId(BlockState holder); - } - - private static Provider blockStateStateId; - - public static void setBlockStateStateId(Provider blockStateStateId) { - BlockStateIdAccess.blockStateStateId = blockStateStateId; - } + private static final BiMap ASSIGNED_IDS = HashBiMap.create(2 << 13); public static OptionalInt getBlockStateId(BlockState holder) { - return blockStateStateId.getBlockStateId(holder); + Integer value = ASSIGNED_IDS.get(holder); + return value == null ? OptionalInt.empty() : OptionalInt.of(value); } public static @Nullable BlockState getBlockStateById(int id) { - return id < blockStates.length ? blockStates[id] : null; + return ASSIGNED_IDS.inverse().get(id); } - private static BlockState[] blockStates = new BlockState[2 << 13]; - - public static void register(BlockState blockState) { - OptionalInt id = getBlockStateId(blockState); + public static void register(BlockState blockState, OptionalInt id) { if (id.isPresent()) { int i = id.getAsInt(); - if (i >= blockStates.length) { - int curLength = blockStates.length; - do { - curLength += curLength >> 1; - } while (i >= curLength); - blockStates = Arrays.copyOf(blockStates, curLength); - } - BlockState existing = blockStates[i]; + BlockState existing = ASSIGNED_IDS.inverse().get(i); checkState(existing == null || existing == blockState, "BlockState %s is using the same block ID (%s) as BlockState %s", blockState, i, existing); - blockStates[i] = blockState; + ASSIGNED_IDS.put(blockState, i); } } + public static void clear() { + ASSIGNED_IDS.clear(); + } + + private BlockStateIdAccess() { + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index aeeae8210..34ffee81c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -27,7 +27,6 @@ import com.google.common.collect.Table; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.registry.BlockRegistry; @@ -38,7 +37,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.OptionalInt; import java.util.Set; /** @@ -47,13 +45,8 @@ import java.util.Set; @SuppressWarnings("unchecked") public class BlockState implements BlockStateHolder { - static { - BlockStateIdAccess.setBlockStateStateId(x -> x.internalId); - } - private final BlockType blockType; private final Map, Object> values; - private OptionalInt internalId = OptionalInt.empty(); private BaseBlock emptyBaseBlock; @@ -66,12 +59,6 @@ public class BlockState implements BlockStateHolder { this.emptyBaseBlock = new BaseBlock(this); } - BlockState initializeId(BlockRegistry registry) { - this.internalId = registry.getInternalBlockStateId(this); - BlockStateIdAccess.register(this); - return this; - } - static Map, Object>, BlockState> generateStateMap(BlockType blockType) { BlockRegistry registry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getRegistries().getBlockRegistry(); Map, Object>, BlockState> stateMap = new LinkedHashMap<>(); @@ -94,14 +81,13 @@ public class BlockState implements BlockStateHolder { valueMap.put(property, value); stateMaker.setState(property, value); } - stateMaker.initializeId(registry); stateMap.put(valueMap, stateMaker); } } if (stateMap.isEmpty()) { // No properties. - stateMap.put(new LinkedHashMap<>(), new BlockState(blockType).initializeId(registry)); + stateMap.put(new LinkedHashMap<>(), new BlockState(blockType)); } for (BlockState state : stateMap.values()) { @@ -114,11 +100,11 @@ public class BlockState implements BlockStateHolder { private void populate(Map, Object>, BlockState> stateMap) { final Table, Object, BlockState> states = HashBasedTable.create(); - for(final Map.Entry, Object> entry : this.values.entrySet()) { + for (final Map.Entry, Object> entry : this.values.entrySet()) { final Property property = (Property) entry.getKey(); property.getValues().forEach(value -> { - if(value != entry.getValue()) { + if (value != entry.getValue()) { BlockState modifiedState = stateMap.get(this.withValue(property, value)); if (modifiedState != null) { states.put(property, value, modifiedState); From 5f5c067081f71a651fbf08014ff5353f1078f899 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Fri, 2 Aug 2019 20:39:24 -0700 Subject: [PATCH 304/366] [Forge] Mark chunks for save after editing biomes --- .../src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java | 1 + 1 file changed, 1 insertion(+) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 542cf884c..6e034e863 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -258,6 +258,7 @@ public class ForgeWorld extends AbstractWorld { return false; } chunk.getBiomes()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = ForgeAdapter.adapt(biome); + chunk.setModified(true); return true; } From 4b54c32f3acf69a4c941eb71ee8db8ffccb961dc Mon Sep 17 00:00:00 2001 From: wizjany Date: Sun, 4 Aug 2019 15:56:16 -0400 Subject: [PATCH 305/366] Skip invalid blocks in schematics. --- .../worldedit/extent/clipboard/io/SpongeSchematicReader.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 b2deb51f0..890d02943 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 @@ -48,6 +48,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.entity.EntityType; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.storage.NBTConversions; @@ -184,8 +185,8 @@ public class SpongeSchematicReader extends NBTSchematicReader { try { state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState(); } catch (InputParseException e) { - throw new IOException("Invalid BlockState in palette: " + palettePart + - ". Are you missing a mod or using a schematic made in a newer version of Minecraft?"); + log.warn("Invalid BlockState in palette: " + palettePart + ". Block will be replaced with air."); + state = BlockTypes.AIR.getDefaultState(); } palette.put(id, state); } From 35edd95c875d0d285d407ebf6a148026254da387 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 5 Aug 2019 14:17:56 -0700 Subject: [PATCH 306/366] [Forge] Update to 28.0.45 for package rename --- worldedit-forge/build.gradle.kts | 2 +- .../main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index 0d68dad28..1c952f5bc 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -13,7 +13,7 @@ applyShadowConfiguration() val minecraftVersion = "1.14.4" val mappingsMinecraftVersion = "1.14.3" -val forgeVersion = "28.0.34" +val forgeVersion = "28.0.45" configurations.all { resolutionStrategy { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java index 0cb76b0ef..e41af9c69 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ThreadSafeCache.java @@ -21,8 +21,8 @@ package com.sk89q.worldedit.forge; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.server.MinecraftServer; +import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.server.ServerLifecycleHooks; import java.util.Collections; @@ -56,7 +56,7 @@ public class ThreadSafeCache { if (now - lastRefresh > REFRESH_DELAY) { Set onlineIds = new HashSet<>(); - + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); if (server == null) { return; From 88803858783802054065e0731a53a2481017fcff Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 5 Aug 2019 14:21:18 -0700 Subject: [PATCH 307/366] [Forge] Switch off of deprecated getEntityPlayer --- .../main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java index a3ad1c9a0..c3f4a8ece 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorldEdit.java @@ -232,8 +232,8 @@ public class ForgeWorldEdit { } WorldEdit we = WorldEdit.getInstance(); - ForgePlayer player = adaptPlayer((ServerPlayerEntity) event.getEntityPlayer()); - ForgeWorld world = getWorld(event.getEntityPlayer().world); + ForgePlayer player = adaptPlayer((ServerPlayerEntity) event.getPlayer()); + ForgeWorld world = getWorld(event.getPlayer().world); if (event instanceof PlayerInteractEvent.LeftClickEmpty) { we.handleArmSwing(player); // this event cannot be canceled From 6ab74dc7e5b1cc96722fa29fe20135fdf08b680e Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 5 Aug 2019 17:39:00 -0400 Subject: [PATCH 308/366] Add missing radius checks. Courtesy @mathiascode. --- .../java/com/sk89q/worldedit/command/GenerationCommands.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 9fcfd2c37..96cf412cf 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 @@ -205,6 +205,7 @@ public class GenerationCommands { @Arg(desc = "The density of the forest, between 0 and 100", def = "5") double density) throws WorldEditException { checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); + worldEdit.checkMaxRadius(size); density /= 100; int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); player.print(affected + " trees created."); @@ -220,6 +221,7 @@ public class GenerationCommands { public int pumpkins(Player player, LocalSession session, EditSession editSession, @Arg(desc = "The size of the patch", def = "10") int size) throws WorldEditException { + worldEdit.checkMaxRadius(size); int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), size); player.print(affected + " pumpkin patches created."); return affected; @@ -252,8 +254,8 @@ public class GenerationCommands { int size, @Switch(name = 'h', desc = "Make a hollow pyramid") boolean hollow) throws WorldEditException { - BlockVector3 pos = session.getPlacementPosition(player); worldEdit.checkMaxRadius(size); + BlockVector3 pos = session.getPlacementPosition(player); int affected = editSession.makePyramid(pos, pattern, size, !hollow); player.findFreePosition(); player.print(affected + " block(s) have been created."); From a1465c02ed56d6870afbb1d09eff0bd92041b58c Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 5 Aug 2019 22:44:51 -0400 Subject: [PATCH 309/366] Make EditSession#center (//center) set even y blocks. At some point this was fixed for x and z but never for y... --- .../src/main/java/com/sk89q/worldedit/EditSession.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 07f4fd795..183f7542f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -1028,8 +1028,10 @@ public class EditSession implements Extent, AutoCloseable { Region centerRegion = new CuboidRegion( getWorld(), // Causes clamping of Y range BlockVector3.at(((int) center.getX()), ((int) center.getY()), ((int) center.getZ())), - BlockVector3.at(MathUtils.roundHalfUp(center.getX()), - center.getY(), MathUtils.roundHalfUp(center.getZ()))); + BlockVector3.at( + MathUtils.roundHalfUp(center.getX()), + MathUtils.roundHalfUp(center.getY()), + MathUtils.roundHalfUp(center.getZ()))); return setBlocks(centerRegion, pattern); } From e25a6d21cd49ef9afabadc786ce794d40120b767 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 3 Aug 2019 12:59:24 -0400 Subject: [PATCH 310/366] Add -e/-b/-m flags to //stack and //move, to match copy and paste. Fixes WORLDEDIT-3935. --- .../java/com/sk89q/worldedit/EditSession.java | 65 +++++++++++++++++-- .../worldedit/command/RegionCommands.java | 45 +++++++++++-- .../extent/buffer/ForgetfulExtentBuffer.java | 57 ++++++++++++++-- .../function/biome/BiomeReplace.java | 19 ++++-- .../function/pattern/BiomePattern.java | 37 +++++++++++ .../worldedit/regions/AbstractFlatRegion.java | 40 ++++++++++++ .../worldedit/world/biome/BiomeType.java | 9 ++- 7 files changed, 253 insertions(+), 19 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BiomePattern.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java 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 183f7542f..aff049e9a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -40,6 +40,7 @@ import com.sk89q.worldedit.extent.world.FastModeExtent; import com.sk89q.worldedit.extent.world.SurvivalModeExtent; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.RegionMaskingFilter; +import com.sk89q.worldedit.function.biome.BiomeReplace; import com.sk89q.worldedit.function.block.BlockDistributionCounter; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.block.Counter; @@ -66,6 +67,7 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.WaterloggedRemover; import com.sk89q.worldedit.function.util.RegionOffset; import com.sk89q.worldedit.function.visitor.DownwardVisitor; +import com.sk89q.worldedit.function.visitor.FlatRegionVisitor; import com.sk89q.worldedit.function.visitor.LayerVisitor; import com.sk89q.worldedit.function.visitor.NonRisingVisitor; import com.sk89q.worldedit.function.visitor.RecursiveVisitor; @@ -1206,7 +1208,8 @@ public class EditSession implements Extent, AutoCloseable { } /** - * Stack a cuboid region. + * Stack a cuboid region. For compatibility, entities are copied by biomes are not. + * Use {@link #stackCuboidRegion(Region, BlockVector3, int, boolean, boolean, Mask)} to fine tune. * * @param region the region to stack * @param dir the direction to stack @@ -1216,6 +1219,23 @@ public class EditSession implements Extent, AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int stackCuboidRegion(Region region, BlockVector3 dir, int count, boolean copyAir) throws MaxChangedBlocksException { + return stackCuboidRegion(region, dir, count, true, false, copyAir ? null : new ExistingBlockMask(this)); + } + + /** + * Stack a cuboid region. + * + * @param region the region to stack + * @param dir the direction to stack + * @param count the number of times to stack + * @param copyEntities true to copy entities + * @param copyBiomes true to copy biomes + * @param mask source mask for the operation (only matching blocks are copied) + * @return number of blocks affected + * @throws MaxChangedBlocksException thrown if too many blocks are changed + */ + public int stackCuboidRegion(Region region, BlockVector3 dir, int count, + boolean copyEntities, boolean copyBiomes, Mask mask) throws MaxChangedBlocksException { checkNotNull(region); checkNotNull(dir); checkArgument(count >= 1, "count >= 1 required"); @@ -1225,8 +1245,10 @@ public class EditSession implements Extent, AutoCloseable { ForwardExtentCopy copy = new ForwardExtentCopy(this, region, this, to); copy.setRepetitions(count); copy.setTransform(new AffineTransform().translate(dir.multiply(size))); - if (!copyAir) { - copy.setSourceMask(new ExistingBlockMask(this)); + copy.setCopyingEntities(copyEntities); + copy.setCopyingBiomes(copyBiomes); + if (mask != null) { + copy.setSourceMask(mask); } Operations.completeLegacy(copy); return copy.getAffected(); @@ -1244,9 +1266,29 @@ public class EditSession implements Extent, AutoCloseable { * @throws MaxChangedBlocksException thrown if too many blocks are changed */ public int moveRegion(Region region, BlockVector3 dir, int distance, boolean copyAir, Pattern replacement) throws MaxChangedBlocksException { + return moveRegion(region, dir, distance, true, false, copyAir ? new ExistingBlockMask(this) : null, replacement); + } + + /** + * Move the blocks in a region a certain direction. + * + * @param region the region to move + * @param dir the direction + * @param distance the distance to move + * @param moveEntities true to move entities + * @param copyBiomes true to copy biomes (source biome is unchanged) + * @param mask source mask for the operation (only matching blocks are moved) + * @param replacement the replacement pattern to fill in after moving, or null to use air + * @return number of blocks moved + * @throws MaxChangedBlocksException thrown if too many blocks are changed + * @throws IllegalArgumentException thrown if the region is not a flat region, but copyBiomes is true + */ + public int moveRegion(Region region, BlockVector3 dir, int distance, + boolean moveEntities, boolean copyBiomes, Mask mask, Pattern replacement) throws MaxChangedBlocksException { checkNotNull(region); checkNotNull(dir); checkArgument(distance >= 1, "distance >= 1 required"); + checkArgument(!copyBiomes || region instanceof FlatRegion, "can't copy biomes from non-flat region"); BlockVector3 to = region.getMinimumPoint(); @@ -1261,9 +1303,13 @@ public class EditSession implements Extent, AutoCloseable { ForwardExtentCopy copy = new ForwardExtentCopy(this, region, buffer, to); copy.setTransform(new AffineTransform().translate(dir.multiply(distance))); copy.setSourceFunction(remove); // Remove - copy.setRemovingEntities(true); - if (!copyAir) { - copy.setSourceMask(new ExistingBlockMask(this)); + + copy.setCopyingEntities(moveEntities); + copy.setRemovingEntities(moveEntities); + copy.setCopyingBiomes(copyBiomes); + + if (mask != null) { + copy.setSourceMask(mask); } // Then we need to copy the buffer to the world @@ -1271,6 +1317,13 @@ public class EditSession implements Extent, AutoCloseable { RegionVisitor visitor = new RegionVisitor(buffer.asRegion(), replace); OperationQueue operation = new OperationQueue(copy, visitor); + + if (copyBiomes) { + BiomeReplace biomeReplace = new BiomeReplace(this, buffer); + FlatRegionVisitor biomeVisitor = new FlatRegionVisitor((FlatRegion) buffer.asRegion(), biomeReplace); + operation.offer(biomeVisitor); + } + Operations.completeLegacy(operation); return copy.getAffected(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 0871f8b8b..e4241dc49 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.generator.FloraGenerator; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.MaskIntersection; import com.sk89q.worldedit.function.mask.NoiseFilter2D; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; @@ -56,6 +57,7 @@ import com.sk89q.worldedit.util.TreeGenerator.TreeType; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; import java.util.ArrayList; @@ -293,10 +295,27 @@ public class RegionCommands { @Switch(name = 's', desc = "Shift the selection to the target location") boolean moveSelection, @Switch(name = 'a', desc = "Ignore air blocks") - boolean ignoreAirBlocks) throws WorldEditException { + boolean ignoreAirBlocks, + @Switch(name = 'e', desc = "Also copy entities") + boolean copyEntities, + @Switch(name = 'b', desc = "Also copy biomes") + boolean copyBiomes, + @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air", def = "") + Mask mask) throws WorldEditException { checkCommandArgument(count >= 1, "Count must be >= 1"); - int affected = editSession.moveRegion(region, direction, count, !ignoreAirBlocks, replace); + Mask combinedMask; + if (ignoreAirBlocks) { + if (mask == null) { + combinedMask = new ExistingBlockMask(editSession); + } else { + combinedMask = new MaskIntersection(mask, new ExistingBlockMask(editSession)); + } + } else { + combinedMask = mask; + } + + int affected = editSession.moveRegion(region, direction, count, copyEntities, copyBiomes, combinedMask, replace); if (moveSelection) { try { @@ -329,8 +348,26 @@ public class RegionCommands { @Switch(name = 's', desc = "Shift the selection to the last stacked copy") boolean moveSelection, @Switch(name = 'a', desc = "Ignore air blocks") - boolean ignoreAirBlocks) throws WorldEditException { - int affected = editSession.stackCuboidRegion(region, direction, count, !ignoreAirBlocks); + boolean ignoreAirBlocks, + @Switch(name = 'e', desc = "Also copy entities") + boolean copyEntities, + @Switch(name = 'b', desc = "Also copy biomes") + boolean copyBiomes, + @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air", def = "") + Mask mask) throws WorldEditException { + + Mask combinedMask; + if (ignoreAirBlocks) { + if (mask == null) { + combinedMask = new ExistingBlockMask(editSession); + } else { + combinedMask = new MaskIntersection(mask, new ExistingBlockMask(editSession)); + } + } else { + combinedMask = mask; + } + + int affected = editSession.stackCuboidRegion(region, direction, count, copyEntities, copyBiomes, combinedMask); if (moveSelection) { try { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java index 0aa410916..299ea5a40 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/buffer/ForgetfulExtentBuffer.java @@ -25,12 +25,17 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.mask.Mask2D; import com.sk89q.worldedit.function.mask.Masks; +import com.sk89q.worldedit.function.pattern.BiomePattern; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.AbstractRegion; +import com.sk89q.worldedit.regions.AbstractFlatRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; @@ -46,12 +51,16 @@ import java.util.Map; *

    This buffer will not attempt to return results from the buffer when * accessor methods (such as {@link #getBlock(BlockVector3)}) are called.

    */ -public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pattern { +public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pattern, BiomePattern { private final Map buffer = new LinkedHashMap<>(); + private final Map biomeBuffer = new LinkedHashMap<>(); private final Mask mask; + private final Mask2D biomeMask; private BlockVector3 min = null; + private BlockVector2 min2d = null; private BlockVector3 max = null; + private BlockVector2 max2d = null; /** * Create a new extent buffer that will buffer every change. @@ -71,9 +80,10 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat */ public ForgetfulExtentBuffer(Extent delegate, Mask mask) { super(delegate); - checkNotNull(delegate); checkNotNull(mask); this.mask = mask; + Mask2D bmask = mask.toMask2D(); + this.biomeMask = bmask == null ? Masks.alwaysTrue2D() : bmask; } @Override @@ -100,6 +110,30 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat } } + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + // Update minimum + if (min2d == null) { + min2d = position; + } else { + min2d = min2d.getMinimum(position); + } + + // Update maximum + if (max2d == null) { + max2d = position; + } else { + max2d = max2d.getMaximum(position); + } + + if (biomeMask.test(position)) { + biomeBuffer.put(position, biome); + return true; + } else { + return getExtent().setBiome(position, biome); + } + } + @Override public BaseBlock apply(BlockVector3 pos) { BaseBlock block = buffer.get(pos); @@ -110,13 +144,23 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat } } + @Override + public BiomeType apply(BlockVector2 pos) { + BiomeType biome = biomeBuffer.get(pos); + if (biome != null) { + return biome; + } else { + return BiomeTypes.OCEAN; + } + } + /** * Return a region representation of this buffer. * * @return a region */ public Region asRegion() { - return new AbstractRegion(null) { + return new AbstractFlatRegion(null) { @Override public BlockVector3 getMinimumPoint() { return min != null ? min : BlockVector3.ZERO; @@ -146,6 +190,11 @@ public class ForgetfulExtentBuffer extends AbstractDelegateExtent implements Pat public Iterator iterator() { return buffer.keySet().iterator(); } + + @Override + public Iterable asFlatRegion() { + return biomeBuffer.keySet(); + } }; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java index efa53f45a..9b98bd48d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/biome/BiomeReplace.java @@ -24,6 +24,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.FlatRegionFunction; +import com.sk89q.worldedit.function.pattern.BiomePattern; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.world.biome.BiomeType; @@ -33,7 +34,7 @@ import com.sk89q.worldedit.world.biome.BiomeType; public class BiomeReplace implements FlatRegionFunction { private final Extent extent; - private BiomeType biome; + private BiomePattern biome; /** * Create a new instance. @@ -42,15 +43,25 @@ public class BiomeReplace implements FlatRegionFunction { * @param biome a biome */ public BiomeReplace(Extent extent, BiomeType biome) { + this(extent, (BiomePattern) biome); + } + + /** + * Create a new instance. + * + * @param extent the extent to apply this function to + * @param pattern the biome pattern to set + */ + public BiomeReplace(Extent extent, BiomePattern pattern) { checkNotNull(extent); - checkNotNull(biome); + checkNotNull(pattern); this.extent = extent; - this.biome = biome; + this.biome = pattern; } @Override public boolean apply(BlockVector2 position) throws WorldEditException { - return extent.setBiome(position, biome); + return extent.setBiome(position, biome.apply(position)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BiomePattern.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BiomePattern.java new file mode 100644 index 000000000..82147f392 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/pattern/BiomePattern.java @@ -0,0 +1,37 @@ +/* + * 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.function.pattern; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.world.biome.BiomeType; + +/** + * Returns a {@link BiomeType} for a given position. + */ +public interface BiomePattern { + + /** + * Return a {@link BiomeType} for the given position. + * + * @param position the position + * @return a block + */ + BiomeType apply(BlockVector2 position); +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java new file mode 100644 index 000000000..a2641d242 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractFlatRegion.java @@ -0,0 +1,40 @@ +/* + * 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.regions; + +import com.sk89q.worldedit.world.World; + +public abstract class AbstractFlatRegion extends AbstractRegion implements FlatRegion { + + protected AbstractFlatRegion(World world) { + super(world); + } + + @Override + public int getMinimumY() { + return getMinimumPoint().getBlockY(); + } + + @Override + public int getMaximumY() { + return getMaximumPoint().getBlockY(); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java index fe9203c70..d2bfab07e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/biome/BiomeType.java @@ -19,13 +19,15 @@ package com.sk89q.worldedit.world.biome; +import com.sk89q.worldedit.function.pattern.BiomePattern; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; /** * All the types of biomes in the game. */ -public class BiomeType implements Keyed { +public class BiomeType implements Keyed, BiomePattern { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("biome type"); @@ -59,4 +61,9 @@ public class BiomeType implements Keyed { public boolean equals(Object obj) { return obj instanceof BiomeType && this.id.equals(((BiomeType) obj).id); } + + @Override + public BiomeType apply(BlockVector2 position) { + return this; + } } From d822ccc9e53a39a03463ee0cd12b5698c22dbff8 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 5 Aug 2019 23:16:42 -0400 Subject: [PATCH 311/366] This is how Mojang checks if trees can grow. Subject to changes. --- .../com/sk89q/worldedit/function/generator/ForestGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java index e45acd24b..4510c2432 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/ForestGenerator.java @@ -53,7 +53,7 @@ public class ForestGenerator implements RegionFunction { BlockState block = editSession.getBlock(position); BlockType t = block.getBlockType(); - if (t == BlockTypes.GRASS_BLOCK || t == BlockTypes.DIRT) { + if (t == BlockTypes.GRASS_BLOCK || t == BlockTypes.DIRT || t == BlockTypes.PODZOL || t == BlockTypes.COARSE_DIRT) { return treeType.generate(editSession, position.add(0, 1, 0)); } else if (t.getMaterial().isReplacedDuringPlacement()) { // since the implementation's tree generators generally don't generate in non-air spots, From bdaffff90a9c9ab185ba738c097023f2c3ae2f68 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 5 Aug 2019 23:25:33 -0400 Subject: [PATCH 312/366] 7.0.1 release candidate 2 --- CHANGELOG.txt | 16 ++++++++++++++++ gradle.properties | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index afa6f8601..057e9eb62 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,19 @@ +7.0.1 Release Candidate 2 +- Improve //thru (and navwand) in some cases +- Fix error when /up was used below the world +- Fix /up -f using glass anyway. +- Fix suggestions for quoted strings +- Improve suggestions for mask intersections +- Fix setting biomes in unloaded chunks +- BlockStateHolder now extends Pattern (API enhancement) +- Skip invalid blocks when schematic versions are mismatched +- Add -e/-b/-m flags to stack and move, just as copy/paste have +- Fix //center for selections with even-sized height +- (Fabric) Fix setting tile entities +- (Forge) Update to latest Forge builds (28.0.45+ required!) +- (Fabric/Forge Single-player) Fix wrong blocks being used when switching +between worlds generated at different times/with different mods + 7.0.1 Release Candidate 1 - Improve //naturalize over large areas - Fixed //restore with 1.14 worlds diff --git a/gradle.properties b/gradle.properties index a2cc53d8e..7773750a5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ group=com.sk89q.worldedit -version=7.0.1-SNAPSHOT +version=7.0.1-rc2 org.gradle.jvmargs=-Xmx1G From 11a532be7463f0b222873391454827928f120232 Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 5 Aug 2019 23:33:02 -0400 Subject: [PATCH 313/366] Back to snapshot. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7773750a5..a2cc53d8e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ group=com.sk89q.worldedit -version=7.0.1-rc2 +version=7.0.1-SNAPSHOT org.gradle.jvmargs=-Xmx1G From 95d5adb30c6e6eee62f55a634101300a9d7ded67 Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 6 Aug 2019 21:49:43 -0400 Subject: [PATCH 314/366] Update docs links to point to enginehub. --- README.md | 2 +- .../com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java | 2 +- worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dbc907064..2cf994bf2 100644 --- a/README.md +++ b/README.md @@ -32,4 +32,4 @@ Links * [IRC channel](https://webchat.esper.net/?join=sk89q) (#sk89q on irc.esper.net) * [Issue tracker](https://dev.enginehub.org/youtrack/issues/WORLDEDIT) * [Continuous integration](http://builds.enginehub.org) [![Build Status](https://ci.enginehub.org/app/rest/builds/buildType:bt10,branch:master/statusIcon.svg)](http://ci.enginehub.org/viewType.html?buildTypeId=bt10&guest=1) -* [End-user documentation](https://worldedit.readthedocs.io/en/latest/) +* [End-user documentation](https://worldedit.enginehub.org/en/latest/) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java index 0dd6003cc..a6f4f0fce 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplLoader.java @@ -54,7 +54,7 @@ public class BukkitImplLoader { "** will be blank, and so on. There will be no support for entity\n" + "** and block property-related functions.\n" + "**\n" + - "** Please see https://worldedit.rtfd.io/en/latest/faq/#bukkit-adapters\n" + + "** Please see https://worldedit.enginehub.org/en/latest/faq/#bukkit-adapters\n" + "**********************************************\n"; /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index 55e36892e..db4d9e0a9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -669,7 +669,7 @@ public final class WorldEdit { engine = new RhinoCraftScriptEngine(); } catch (NoClassDefFoundError ignored) { player.printError("Failed to find an installed script engine."); - player.printError("Please see https://worldedit.readthedocs.io/en/latest/usage/other/craftscripts/"); + player.printError("Please see https://worldedit.enginehub.org/en/latest/usage/other/craftscripts/"); return; } From 17cfdee347a0b9f9619b4ce13587378959c2c6ba Mon Sep 17 00:00:00 2001 From: wizjany Date: Tue, 6 Aug 2019 23:07:26 -0400 Subject: [PATCH 315/366] Update/remove more dead links. --- contrib/craftscripts/README.txt | 5 ++--- .../java/com/sk89q/wepif/PermissionsResolverManager.java | 4 ---- worldedit-bukkit/src/main/resources/plugin.yml | 3 --- worldedit-forge/src/main/resources/META-INF/mods.toml | 2 +- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/contrib/craftscripts/README.txt b/contrib/craftscripts/README.txt index 7638e67ed..c44072d8f 100644 --- a/contrib/craftscripts/README.txt +++ b/contrib/craftscripts/README.txt @@ -6,10 +6,9 @@ Example usage: You may or may not install these scripts -- it is optional. If you are, however, place the entire craftscripts/ folder into the respective directory for the platform -that you have installed WorldEdit for -(see http://wiki.sk89q.com/wiki/WorldEdit/Installation). +that you have installed WorldEdit. In order to be able to use CraftScripts, you must install the Rhino JavaScript library. The installation page linked above has information about that. More information about scripts in general can be found at -http://wiki.sk89q.com/wiki/WorldEdit/Scripting \ No newline at end of file +https://worldedit.enginehub.org/en/latest/usage/other/craftscripts/ \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/sk89q/wepif/PermissionsResolverManager.java b/worldedit-bukkit/src/main/java/com/sk89q/wepif/PermissionsResolverManager.java index 6514912a8..68903f9c3 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/wepif/PermissionsResolverManager.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/wepif/PermissionsResolverManager.java @@ -57,10 +57,6 @@ public class PermissionsResolverManager implements PermissionsResolver { "# into WEPIF, paste it into http://yaml-online-parser.appspot.com/\r\n" + "# and see if it gives \"ERROR:\".\r\n" + "# - Lines starting with # are comments and so they are ignored.\r\n" + - "#\r\n" + - "# About Configuration Permissions\r\n" + - "# - See http://wiki.sk89q.com/wiki/WorldEdit/Permissions/Bukkit\r\n" + - "# - Now with multiworld support (see example)\r\n" + "\r\n"; private static PermissionsResolverManager instance; diff --git a/worldedit-bukkit/src/main/resources/plugin.yml b/worldedit-bukkit/src/main/resources/plugin.yml index 27808257f..600656239 100644 --- a/worldedit-bukkit/src/main/resources/plugin.yml +++ b/worldedit-bukkit/src/main/resources/plugin.yml @@ -3,6 +3,3 @@ main: com.sk89q.worldedit.bukkit.WorldEditPlugin version: "${internalVersion}" load: STARTUP api-version: 1.13 - -# Permissions aren't here. Read http://wiki.sk89q.com/wiki/WEPIF/DinnerPerms -# for how WorldEdit permissions actually work. diff --git a/worldedit-forge/src/main/resources/META-INF/mods.toml b/worldedit-forge/src/main/resources/META-INF/mods.toml index 07b5ff1a0..1f6e628a7 100644 --- a/worldedit-forge/src/main/resources/META-INF/mods.toml +++ b/worldedit-forge/src/main/resources/META-INF/mods.toml @@ -5,7 +5,7 @@ loaderVersion="[24,)" # A URL to refer people to when problems occur with this mod issueTrackerURL="https://discord.gg/enginehub" # A URL for the "homepage" for this mod, displayed in the mod UI -displayURL="http://wiki.sk89q.com/wiki/WorldEdit/" +displayURL="https://worldedit.enginehub.org/" # A file name (in the root of the mod JAR) containing a logo for display logoFile="worldedit-icon.png" # A text field displayed in the mod UI From 0e25839490fefeffabae83b206b9b374b0fa85f0 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 8 Aug 2019 10:14:16 -0400 Subject: [PATCH 316/366] Fix schematic list box loading schems with spaces in path. --- .../java/com/sk89q/worldedit/command/SchematicCommands.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a2b59ffbd..07425d35a 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 @@ -434,7 +434,7 @@ public class SchematicCommands { .content("") .append(TextComponent.of("[L]") .color(TextColor.GOLD) - .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load " + path)) + .clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load \"" + path + "\"")) .hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load")))) .append(TextComponent.space()) .append(TextComponent.of(path) From f83de2a7032cd52035aac64b469ddbba8822487b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 8 Aug 2019 16:28:00 -0700 Subject: [PATCH 317/366] Fix bug with spaces at end of suggestions. --- .../sk89q/worldedit/internal/command/CommandUtil.java | 10 +++++++--- .../com/sk89q/worldedit/internal/util/Substring.java | 8 ++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java index b259435a1..bdcd8e541 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java @@ -70,14 +70,18 @@ public class CommandUtil { ); return suggestions.stream() // Re-map suggestions to only operate on the last non-quoted word - .map(CommandUtil::onlyOnLastQuotedWord) - .map(suggestion -> CommandUtil.suggestLast(lastArg, suggestion)) + .map(suggestion -> onlyOnLastQuotedWord(lastArg, suggestion)) + .map(suggestion -> suggestLast(lastArg, suggestion)) .filter(Optional::isPresent) .map(Optional::get) .collect(toList()); } - private static Substring onlyOnLastQuotedWord(Substring suggestion) { + private static Substring onlyOnLastQuotedWord(Substring lastArg, Substring suggestion) { + if (suggestion.getSubstring().startsWith(lastArg.getSubstring())) { + // This is already fine. + return suggestion; + } String substr = suggestion.getSubstring(); int sp = substr.lastIndexOf(' '); if (sp < 0) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/Substring.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/Substring.java index fa4049cda..0ffe91d71 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/Substring.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/util/Substring.java @@ -21,6 +21,8 @@ package com.sk89q.worldedit.internal.util; import java.util.Objects; +import static com.google.common.base.Preconditions.checkArgument; + /** * An explicit substring. Provides the range from which it was taken. */ @@ -31,7 +33,7 @@ public final class Substring { * a Substring. */ public static Substring from(String original, int start) { - return wrap(original.substring(start), start, original.length()); + return new Substring(original.substring(start), start, original.length()); } /** @@ -39,13 +41,15 @@ public final class Substring { * a Substring. */ public static Substring from(String original, int start, int end) { - return wrap(original.substring(start, end), start, end); + return new Substring(original.substring(start, end), start, end); } /** * Wrap the given parameters into a Substring instance. */ public static Substring wrap(String substring, int start, int end) { + checkArgument(0 <= start, "Start must be greater than or equal to zero"); + checkArgument(start <= end, "End must be greater than or equal to start"); return new Substring(substring, start, end); } From 61bc012f6fc78fd34b652d6fbd6032653daeee95 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 10 Aug 2019 11:54:22 -0400 Subject: [PATCH 318/366] Fix source masks using EditSession instead of clipboard. (#515) --- .../worldedit/command/BrushCommands.java | 7 +++- .../worldedit/command/ClipboardCommands.java | 2 + .../command/argument/FactoryConverter.java | 42 +++++++++++++++++-- .../factory/parser/mask/BiomeMaskParser.java | 3 +- .../parser/mask/BlockCategoryMaskParser.java | 3 +- .../parser/mask/BlockStateMaskParser.java | 3 +- .../factory/parser/mask/BlocksMaskParser.java | 3 +- .../parser/mask/ExistingMaskParser.java | 3 +- .../parser/mask/ExpressionMaskParser.java | 3 +- .../factory/parser/mask/OffsetMaskParser.java | 3 +- .../factory/parser/mask/SolidMaskParser.java | 3 +- .../internal/annotation/ClipboardMask.java | 37 ++++++++++++++++ 12 files changed, 91 insertions(+), 21 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/ClipboardMask.java 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 25f198e92..9b8e35dae 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 @@ -48,6 +48,7 @@ import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.ClipboardMask; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.factory.RegionFactory; import com.sk89q.worldedit.session.ClipboardHolder; @@ -156,9 +157,13 @@ public class BrushCommands { @Switch(name = 'b', desc = "Paste biomes if available") boolean pasteBiomes, @ArgFlag(name = 'm', desc = "Skip blocks matching this mask in the clipboard", def = "") + @ClipboardMask Mask sourceMask) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); + Clipboard clipboard = holder.getClipboard(); + ClipboardHolder newHolder = new ClipboardHolder(clipboard); + newHolder.setTransform(holder.getTransform()); BlockVector3 size = clipboard.getDimensions(); @@ -167,7 +172,7 @@ public class BrushCommands { worldEdit.checkMaxBrushRadius(size.getBlockZ() / 2D - 1); BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()); - tool.setBrush(new ClipboardBrush(holder, ignoreAir, usingOrigin, pasteEntities, pasteBiomes, sourceMask), "worldedit.brush.clipboard"); + tool.setBrush(new ClipboardBrush(newHolder, ignoreAir, usingOrigin, pasteEntities, pasteBiomes, sourceMask), "worldedit.brush.clipboard"); player.print("Clipboard brush shape equipped."); } 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 d2b9f7747..70bbd29de 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 @@ -35,6 +35,7 @@ import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.ClipboardMask; import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.math.BlockVector3; @@ -143,6 +144,7 @@ public class ClipboardCommands { @Switch(name = 'b', desc = "Paste biomes if available") boolean pasteBiomes, @ArgFlag(name = 'm', desc = "Only paste blocks matching this mask", def = "") + @ClipboardMask Mask sourceMask) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index d6259abf3..8b5a56f0c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.command.argument; +import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseItem; @@ -27,9 +28,14 @@ import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.transform.BlockTransformExtent; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.annotation.ClipboardMask; import com.sk89q.worldedit.internal.registry.AbstractFactory; +import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.World; @@ -41,30 +47,53 @@ import org.enginehub.piston.converter.SuccessfulConversion; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; +import javax.annotation.Nullable; import java.util.List; +import java.util.function.Consumer; import java.util.function.Function; public class FactoryConverter implements ArgumentConverter { public static void register(WorldEdit worldEdit, CommandManager commandManager) { commandManager.registerConverter(Key.of(Pattern.class), - new FactoryConverter<>(worldEdit, WorldEdit::getPatternFactory, "pattern")); + new FactoryConverter<>(worldEdit, WorldEdit::getPatternFactory, "pattern", null)); commandManager.registerConverter(Key.of(Mask.class), - new FactoryConverter<>(worldEdit, WorldEdit::getMaskFactory, "mask")); + new FactoryConverter<>(worldEdit, WorldEdit::getMaskFactory, "mask", null)); commandManager.registerConverter(Key.of(BaseItem.class), - new FactoryConverter<>(worldEdit, WorldEdit::getItemFactory, "item")); + new FactoryConverter<>(worldEdit, WorldEdit::getItemFactory, "item", null)); + + commandManager.registerConverter(Key.of(Mask.class, ClipboardMask.class), + new FactoryConverter<>(worldEdit, WorldEdit::getMaskFactory, "mask", + context -> { + try { + ClipboardHolder holder = context.getSession().getClipboard(); + Transform transform = holder.getTransform(); + Extent target; + if (transform.isIdentity()) { + target = holder.getClipboard(); + } else { + target = new BlockTransformExtent(holder.getClipboard(), transform); + } + context.setExtent(target); + } catch (EmptyClipboardException e) { + throw new IllegalStateException(e); + } + })); } private final WorldEdit worldEdit; private final Function> factoryExtractor; private final String description; + @Nullable private final Consumer contextTweaker; private FactoryConverter(WorldEdit worldEdit, Function> factoryExtractor, - String description) { + String description, + @Nullable Consumer contextTweaker) { this.worldEdit = worldEdit; this.factoryExtractor = factoryExtractor; this.description = description; + this.contextTweaker = contextTweaker; } @Override @@ -80,10 +109,15 @@ public class FactoryConverter implements ArgumentConverter { if (extent instanceof World) { parserContext.setWorld((World) extent); } + parserContext.setExtent(new RequestExtent()); } parserContext.setSession(session); parserContext.setRestricted(true); + if (contextTweaker != null) { + contextTweaker.accept(parserContext); + } + try { return SuccessfulConversion.fromSingle( factoryExtractor.apply(worldEdit).parseFromInput(argument, parserContext) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java index 9e38e2e82..b578fd031 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BiomeMaskParser.java @@ -28,7 +28,6 @@ import com.sk89q.worldedit.function.mask.BiomeMask2D; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.internal.registry.InputParser; -import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.world.biome.BiomeType; import java.util.Arrays; @@ -78,6 +77,6 @@ public class BiomeMaskParser extends InputParser { biomes.add(biome); } - return Masks.asMask(new BiomeMask2D(new RequestExtent(), biomes)); + return Masks.asMask(new BiomeMask2D(context.getExtent(), biomes)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java index ee7bebf44..5fa9033b2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockCategoryMaskParser.java @@ -26,7 +26,6 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.BlockCategoryMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.registry.InputParser; -import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.world.block.BlockCategory; import java.util.Locale; @@ -54,7 +53,7 @@ public class BlockCategoryMaskParser extends InputParser { if (category == null) { throw new InputParseException("Unrecognised tag '" + input.substring(2) + '\''); } else { - return new BlockCategoryMask(new RequestExtent(), category); + return new BlockCategoryMask(context.getExtent(), category); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java index 95884b821..ca47294b4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlockStateMaskParser.java @@ -26,7 +26,6 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.BlockStateMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.registry.InputParser; -import com.sk89q.worldedit.session.request.RequestExtent; import java.util.stream.Stream; @@ -53,7 +52,7 @@ public class BlockStateMaskParser extends InputParser { boolean strict = input.charAt(1) == '='; String states = input.substring(2 + (strict ? 1 : 0), input.length() - 1); try { - return new BlockStateMask(new RequestExtent(), + return new BlockStateMask(context.getExtent(), Splitter.on(',').omitEmptyStrings().trimResults().withKeyValueSeparator('=').split(states), strict); } catch (Exception e) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java index 8580eb8a1..c4208dd94 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/BlocksMaskParser.java @@ -26,7 +26,6 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.registry.InputParser; -import com.sk89q.worldedit.session.request.RequestExtent; import com.sk89q.worldedit.world.block.BaseBlock; import java.util.Set; @@ -56,7 +55,7 @@ public class BlocksMaskParser extends InputParser { if (holders.isEmpty()) { return null; } - return new BlockMask(new RequestExtent(), holders); + return new BlockMask(context.getExtent(), holders); } catch (NoMatchException e) { return null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java index 21feb6449..1f55824ae 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExistingMaskParser.java @@ -25,7 +25,6 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.registry.SimpleInputParser; -import com.sk89q.worldedit.session.request.RequestExtent; import java.util.List; @@ -44,6 +43,6 @@ public class ExistingMaskParser extends SimpleInputParser { @Override public Mask parseFromSimpleInput(String input, ParserContext context) { - return new ExistingBlockMask(new RequestExtent()); + return new ExistingBlockMask(context.getExtent()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java index ac104e198..7438e2759 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/ExpressionMaskParser.java @@ -30,7 +30,6 @@ import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; import com.sk89q.worldedit.session.SessionOwner; -import com.sk89q.worldedit.session.request.RequestExtent; import java.util.function.IntSupplier; import java.util.stream.Stream; @@ -58,7 +57,7 @@ public class ExpressionMaskParser extends InputParser { try { Expression exp = Expression.compile(input.substring(1), "x", "y", "z"); WorldEditExpressionEnvironment env = new WorldEditExpressionEnvironment( - new RequestExtent(), Vector3.ONE, Vector3.ZERO); + context.getExtent(), Vector3.ONE, Vector3.ZERO); exp.setEnvironment(env); if (context.getActor() != null) { SessionOwner owner = context.getActor(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java index ede9b6c79..b6c222f2e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/OffsetMaskParser.java @@ -29,7 +29,6 @@ import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.OffsetMask; import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.session.request.RequestExtent; import java.util.stream.Stream; @@ -62,7 +61,7 @@ public class OffsetMaskParser extends InputParser { if (input.length() > 1) { submask = worldEdit.getMaskFactory().parseFromInput(input.substring(1), context); } else { - submask = new ExistingBlockMask(new RequestExtent()); + submask = new ExistingBlockMask(context.getExtent()); } OffsetMask offsetMask = new OffsetMask(submask, BlockVector3.at(0, firstChar == '>' ? -1 : 1, 0)); return new MaskIntersection(offsetMask, Masks.negate(submask)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java index f5ae3244a..412240a64 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/factory/parser/mask/SolidMaskParser.java @@ -25,7 +25,6 @@ import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.internal.registry.SimpleInputParser; -import com.sk89q.worldedit.session.request.RequestExtent; import java.util.List; @@ -44,6 +43,6 @@ public class SolidMaskParser extends SimpleInputParser { @Override public Mask parseFromSimpleInput(String input, ParserContext context) { - return new SolidBlockMask(new RequestExtent()); + return new SolidBlockMask(context.getExtent()); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/ClipboardMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/ClipboardMask.java new file mode 100644 index 000000000..6b8be85e0 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/annotation/ClipboardMask.java @@ -0,0 +1,37 @@ +/* + * 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.internal.annotation; + +import com.sk89q.worldedit.function.mask.Mask; +import org.enginehub.piston.inject.InjectAnnotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates a {@link Mask} parameter to use the clipboard as the extent instead of target World/EditSession. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@InjectAnnotation +public @interface ClipboardMask { +} From 22cf93c31fe4ca31a708b742d15f73d59786d94d Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 12 Aug 2019 21:35:09 +1000 Subject: [PATCH 319/366] Bump to 7.0.1 --- CHANGELOG.txt | 9 +++++---- gradle.properties | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 057e9eb62..239493387 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,7 @@ -7.0.1 Release Candidate 2 +7.0.1 +- Fix source masks using EdiSession instead of clipboard +- Fix bug with spaces in suggestions +- Fix schematic list box loading schematics with spaces in path - Improve //thru (and navwand) in some cases - Fix error when /up was used below the world - Fix /up -f using glass anyway. @@ -13,8 +16,6 @@ - (Forge) Update to latest Forge builds (28.0.45+ required!) - (Fabric/Forge Single-player) Fix wrong blocks being used when switching between worlds generated at different times/with different mods - -7.0.1 Release Candidate 1 - Improve //naturalize over large areas - Fixed //restore with 1.14 worlds - Added item brush support to WorldEdit for Bukkit (Formerly just Forge) @@ -33,7 +34,7 @@ between worlds generated at different times/with different mods - Fixed setting player heads with names - Added a mask flag to //count - Setup pagination for //distr -- Fixed an entity-related error being caused by plugins improperly using Spigot. +- Fixed an entity-related error being caused by plugins improperly using Spigot - Fixed gravity brush - Modify chunk batching for performance - Further legacy schematic loading improvements diff --git a/gradle.properties b/gradle.properties index a2cc53d8e..f7228d7fb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ group=com.sk89q.worldedit -version=7.0.1-SNAPSHOT +version=7.0.1 org.gradle.jvmargs=-Xmx1G From ec5bc5a3b7fb8de131417cac00b69ed1eb7f35b1 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 12 Aug 2019 21:48:15 +1000 Subject: [PATCH 320/366] Bump to 7.1.0-SNAPSHOT for continued development --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f7228d7fb..4d41d3dcb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ group=com.sk89q.worldedit -version=7.0.1 +version=7.1.0-SNAPSHOT org.gradle.jvmargs=-Xmx1G From f472c20bfbb125361834cfeb36650f493b17f0c0 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 12 Aug 2019 05:06:40 -0700 Subject: [PATCH 321/366] Memory optimizations (#505) * Remove LocatedBlock overhead in LBL map * Add new space-efficient block map, with thourough testing * Drop ordering property, add full insertion test * Add licenses * Fix mocked platform conflicts * Disable full block map testing for faster builds * Re-implement BlockMap with fastutil maps * Re-write chunk batching to be memory efficient * Make MultiStageReorder use BlockMap * Increase LBL load factor, fix long-pack limit detection * Fix infinite loop in chunk batching * Save memory in history by cleaning up MSR * Re-implement LocatedBlockList in BlockMap * Fix data race with BlockType lazy fields * Make IDs ALWAYS present, only runtime-consistent. Use for memory efficiency in BlockMap * Remap inner structure of BlockMap for smaller maps * Remove containedBlocks fields, not very efficient * Fix minor de-optimizing bug in stage reorder * Make long packed y signed * Add extended Y limit configuration option * Add licenses * Store 3 ints for unoptimized BV list * Add final to BitMath * Correct int-cast for long-packing --- buildSrc/src/main/kotlin/PlatformConfig.kt | 3 + buildSrc/src/main/kotlin/Versions.kt | 1 + config/checkstyle/import-control.xml | 1 + worldedit-bukkit/build.gradle.kts | 3 + worldedit-core/build.gradle.kts | 2 +- .../sk89q/worldedit/LocalConfiguration.java | 1 + .../extent/reorder/ChunkBatchingExtent.java | 63 +- .../extent/reorder/MultiStageReorder.java | 38 +- .../function/operation/SetBlockMap.java | 60 ++ .../internal/block/BlockStateIdAccess.java | 33 +- .../com/sk89q/worldedit/math/BitMath.java | 52 ++ .../sk89q/worldedit/math/BlockVector3.java | 34 + .../math/RegionOptimizedChunkComparator.java | 41 ++ .../math/RegionOptimizedComparator.java | 36 ++ .../util/PropertiesConfiguration.java | 1 + .../worldedit/util/YAMLConfiguration.java | 1 + .../worldedit/util/collection/BlockMap.java | 427 +++++++++++++ .../util/collection/LocatedBlockList.java | 42 +- .../util/collection/LongPositionList.java | 91 +++ .../util/collection/PositionList.java | 47 ++ .../util/collection/SubBlockMap.java | 194 ++++++ .../util/collection/VectorPositionList.java | 98 +++ .../util/concurrency/LazyReference.java | 75 +++ .../worldedit/world/block/BlockState.java | 3 - .../worldedit/world/block/BlockType.java | 63 +- .../internal/expression/ExpressionTest.java | 15 +- .../worldedit/util/VariedVectorsProvider.java | 133 ++++ .../util/collection/BlockMapTest.java | 588 ++++++++++++++++++ .../test/resources/junit-platform.properties | 5 + .../config/ConfigurateConfiguration.java | 2 + 30 files changed, 2014 insertions(+), 139 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/SetBlockMap.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/math/BitMath.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/math/RegionOptimizedChunkComparator.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/math/RegionOptimizedComparator.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LongPositionList.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/PositionList.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/SubBlockMap.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/util/concurrency/LazyReference.java create mode 100644 worldedit-core/src/test/java/com/sk89q/worldedit/util/VariedVectorsProvider.java create mode 100644 worldedit-core/src/test/java/com/sk89q/worldedit/util/collection/BlockMapTest.java create mode 100644 worldedit-core/src/test/resources/junit-platform.properties diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index c5deea857..beb159945 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -46,6 +46,9 @@ fun Project.applyPlatformAndCoreConfiguration() { dependencies { "testImplementation"("org.junit.jupiter:junit-jupiter-api:${Versions.JUNIT}") + "testImplementation"("org.junit.jupiter:junit-jupiter-params:${Versions.JUNIT}") + "testImplementation"("org.mockito:mockito-core:${Versions.MOCKITO}") + "testImplementation"("org.mockito:mockito-junit-jupiter:${Versions.MOCKITO}") "testRuntime"("org.junit.jupiter:junit-jupiter-engine:${Versions.JUNIT}") } diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index e0c2b4763..b460f77eb 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -4,4 +4,5 @@ object Versions { const val PISTON = "0.4.3" const val AUTO_VALUE = "1.6.5" const val JUNIT = "5.5.0" + const val MOCKITO = "3.0.0" } diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 27b054a03..e26e9a388 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -40,6 +40,7 @@ + diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 1343ff2be..cb859fb6a 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -63,6 +63,9 @@ tasks.named("shadowJar") { relocate("io.papermc.lib", "com.sk89q.worldedit.bukkit.paperlib") { include(dependency("io.papermc:paperlib:1.0.2")) } + relocate("it.unimi.dsi.fastutil", "com.sk89q.worldedit.bukkit.fastutil") { + include(dependency("it.unimi.dsi:fastutil")) + } } } diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index 274cf2e06..a20b254f8 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -21,6 +21,7 @@ dependencies { "compile"("com.google.code.findbugs:jsr305:1.3.9") "compile"("com.google.code.gson:gson:2.8.0") "compile"("org.slf4j:slf4j-api:1.7.26") + "compile"("it.unimi.dsi:fastutil:8.2.1") "compileOnly"(project(":worldedit-libs:core:ap")) "annotationProcessor"(project(":worldedit-libs:core:ap")) @@ -28,7 +29,6 @@ dependencies { "annotationProcessor"("com.google.guava:guava:21.0") "compileOnly"("com.google.auto.value:auto-value-annotations:${Versions.AUTO_VALUE}") "annotationProcessor"("com.google.auto.value:auto-value:${Versions.AUTO_VALUE}") - "testCompile"("org.mockito:mockito-core:1.9.0-rc1") } tasks.withType().configureEach { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java index d814bf48b..0b042c8bb 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalConfiguration.java @@ -75,6 +75,7 @@ public abstract class LocalConfiguration { public int butcherMaxRadius = -1; public boolean allowSymlinks = false; public boolean serverSideCUI = true; + public boolean extendedYLimit = false; protected String[] getDefaultDisallowedBlocks() { List blockTypes = Lists.newArrayList( diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java index a44017fd1..591cb936b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/ChunkBatchingExtent.java @@ -19,25 +19,21 @@ package com.sk89q.worldedit.extent.reorder; -import com.google.common.collect.Table; -import com.google.common.collect.TreeBasedTable; +import com.google.common.collect.ImmutableSortedSet; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.AbstractBufferingExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.RunContext; -import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.RegionOptimizedComparator; +import com.sk89q.worldedit.util.collection.BlockMap; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; -import java.util.Comparator; -import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.Set; /** * A special extent that batches changes into Minecraft chunks. This helps @@ -47,17 +43,7 @@ import java.util.Set; */ public class ChunkBatchingExtent extends AbstractBufferingExtent { - /** - * Comparator optimized for sorting chunks by the region file they reside - * in. This allows for file caches to be used while loading the chunk. - */ - private static final Comparator REGION_OPTIMIZED_SORT = - Comparator.comparing((BlockVector2 vec) -> vec.shr(5), BlockVector2.COMPARING_GRID_ARRANGEMENT) - .thenComparing(BlockVector2.COMPARING_GRID_ARRANGEMENT); - - private final Table batches = - TreeBasedTable.create(REGION_OPTIMIZED_SORT, BlockVector3.sortByCoordsYzx()); - private final Set containedBlocks = new HashSet<>(); + private final BlockMap blockMap = BlockMap.create(); private boolean enabled; public ChunkBatchingExtent(Extent extent) { @@ -81,32 +67,18 @@ public class ChunkBatchingExtent extends AbstractBufferingExtent { return enabled; } - private BlockVector2 getChunkPos(BlockVector3 location) { - return location.shr(4).toBlockVector2(); - } - - private BlockVector3 getInChunkPos(BlockVector3 location) { - return BlockVector3.at(location.getX() & 15, location.getY(), location.getZ() & 15); - } - @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { if (!enabled) { return setDelegateBlock(location, block); } - BlockVector2 chunkPos = getChunkPos(location); - BlockVector3 inChunkPos = getInChunkPos(location); - batches.put(chunkPos, inChunkPos, block.toBaseBlock()); - containedBlocks.add(location); + blockMap.put(location, block.toBaseBlock()); return true; } @Override protected Optional getBufferedBlock(BlockVector3 position) { - if (!containedBlocks.contains(position)) { - return Optional.empty(); - } - return Optional.of(batches.get(getChunkPos(position), getInChunkPos(position))); + return Optional.ofNullable(blockMap.get(position)); } @Override @@ -117,24 +89,21 @@ public class ChunkBatchingExtent extends AbstractBufferingExtent { return new Operation() { // we get modified between create/resume -- only create this on resume to prevent CME - private Iterator>> batchIterator; + private Iterator iterator; @Override public Operation resume(RunContext run) throws WorldEditException { - if (batchIterator == null) { - batchIterator = batches.rowMap().entrySet().iterator(); + if (iterator == null) { + iterator = ImmutableSortedSet.copyOf(RegionOptimizedComparator.INSTANCE, + blockMap.keySet()).iterator(); } - if (!batchIterator.hasNext()) { - return null; + while (iterator.hasNext()) { + BlockVector3 position = iterator.next(); + BaseBlock block = blockMap.get(position); + getExtent().setBlock(position, block); } - Map.Entry> next = batchIterator.next(); - BlockVector3 chunkOffset = next.getKey().toBlockVector3().shl(4); - for (Map.Entry block : next.getValue().entrySet()) { - getExtent().setBlock(block.getKey().add(chunkOffset), block.getValue()); - containedBlocks.remove(block.getKey()); - } - batchIterator.remove(); - return this; + blockMap.clear(); + return null; } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java index 011640709..733d6c7de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/reorder/MultiStageReorder.java @@ -24,9 +24,10 @@ import com.sk89q.worldedit.extent.AbstractBufferingExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.OperationQueue; -import com.sk89q.worldedit.function.operation.SetLocatedBlocks; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.function.operation.SetBlockMap; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.collection.LocatedBlockList; +import com.sk89q.worldedit.util.collection.BlockMap; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockCategories; import com.sk89q.worldedit.world.block.BlockState; @@ -36,12 +37,10 @@ import com.sk89q.worldedit.world.block.BlockTypes; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.Set; /** * Re-orders blocks into several stages. @@ -143,8 +142,7 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde priorityMap.put(BlockTypes.MOVING_PISTON, PlacementPriority.FINAL); } - private final Set containedBlocks = new HashSet<>(); - private Map stages = new HashMap<>(); + private Map stages = new HashMap<>(); private boolean enabled; @@ -178,7 +176,7 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde this.enabled = enabled; for (PlacementPriority priority : PlacementPriority.values()) { - stages.put(priority, new LocatedBlockList()); + stages.put(priority, BlockMap.create()); } } @@ -220,7 +218,7 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde return setDelegateBlock(location, block); } - BlockState existing = getBlock(location); + BlockState existing = getExtent().getBlock(location); PlacementPriority priority = getPlacementPriority(block); PlacementPriority srcPriority = getPlacementPriority(existing); @@ -229,13 +227,13 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde switch (srcPriority) { case FINAL: - stages.get(PlacementPriority.CLEAR_FINAL).add(location, replacement); + stages.get(PlacementPriority.CLEAR_FINAL).put(location, replacement); break; case LATE: - stages.get(PlacementPriority.CLEAR_LATE).add(location, replacement); + stages.get(PlacementPriority.CLEAR_LATE).put(location, replacement); break; case LAST: - stages.get(PlacementPriority.CLEAR_LAST).add(location, replacement); + stages.get(PlacementPriority.CLEAR_LAST).put(location, replacement); break; } @@ -244,16 +242,12 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde } } - stages.get(priority).add(location, block); - containedBlocks.add(location); + stages.get(priority).put(location, block.toBaseBlock()); return !existing.equalsFuzzy(block); } @Override protected Optional getBufferedBlock(BlockVector3 position) { - if (!containedBlocks.contains(position)) { - return Optional.empty(); - } return stages.values().stream() .map(blocks -> blocks.get(position)) .filter(Objects::nonNull) @@ -267,7 +261,17 @@ public class MultiStageReorder extends AbstractBufferingExtent implements Reorde } List operations = new ArrayList<>(); for (PlacementPriority priority : PlacementPriority.values()) { - operations.add(new SetLocatedBlocks(getExtent(), stages.get(priority))); + BlockMap blocks = stages.get(priority); + operations.add(new SetBlockMap(getExtent(), blocks) { + @Override + public Operation resume(RunContext run) throws WorldEditException { + Operation operation = super.resume(run); + if (operation == null) { + blocks.clear(); + } + return operation; + } + }); } return new OperationQueue(operations); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/SetBlockMap.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/SetBlockMap.java new file mode 100644 index 000000000..863aadd03 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/operation/SetBlockMap.java @@ -0,0 +1,60 @@ +/* + * 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.function.operation; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.LocatedBlock; +import com.sk89q.worldedit.util.collection.BlockMap; +import com.sk89q.worldedit.world.block.BaseBlock; + +import java.util.List; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class SetBlockMap implements Operation { + + private final Extent extent; + private final BlockMap blocks; + + public SetBlockMap(Extent extent, BlockMap blocks) { + this.extent = checkNotNull(extent); + this.blocks = checkNotNull(blocks); + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + for (Map.Entry entry : blocks.entrySet()) { + extent.setBlock(entry.getKey(), entry.getValue()); + } + return null; + } + + @Override + public void cancel() { + } + + @Override + public void addStatusMessages(List messages) { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java index dcd8210b0..c62b96225 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/block/BlockStateIdAccess.java @@ -22,10 +22,10 @@ package com.sk89q.worldedit.internal.block; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.registry.BlockRegistry; import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.Map; +import java.util.BitSet; import java.util.OptionalInt; import static com.google.common.base.Preconditions.checkState; @@ -43,19 +43,32 @@ public final class BlockStateIdAccess { return ASSIGNED_IDS.inverse().get(id); } + /** + * For platforms that don't have an internal ID system, + * {@link BlockRegistry#getInternalBlockStateId(BlockState)} will return + * {@link OptionalInt#empty()}. In those cases, we will use our own ID system, + * since it's useful for other entries as well. + * @return an unused ID in WorldEdit's ID tracker + */ + private static int provideUnusedWorldEditId() { + return usedIds.nextClearBit(0); + } + + private static final BitSet usedIds = new BitSet(); + public static void register(BlockState blockState, OptionalInt id) { - if (id.isPresent()) { - int i = id.getAsInt(); - BlockState existing = ASSIGNED_IDS.inverse().get(i); - checkState(existing == null || existing == blockState, - "BlockState %s is using the same block ID (%s) as BlockState %s", - blockState, i, existing); - ASSIGNED_IDS.put(blockState, i); - } + int i = id.orElseGet(BlockStateIdAccess::provideUnusedWorldEditId); + BlockState existing = ASSIGNED_IDS.inverse().get(i); + checkState(existing == null || existing == blockState, + "BlockState %s is using the same block ID (%s) as BlockState %s", + blockState, i, existing); + ASSIGNED_IDS.put(blockState, i); + usedIds.set(i); } public static void clear() { ASSIGNED_IDS.clear(); + usedIds.clear(); } private BlockStateIdAccess() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BitMath.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BitMath.java new file mode 100644 index 000000000..46fa66e73 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BitMath.java @@ -0,0 +1,52 @@ +/* + * 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.math; + +public final class BitMath { + + public static int mask(int bits) { + return ~(~0 << bits); + } + + public static int unpackX(long packed) { + return extractSigned(packed, 0, 26); + } + + public static int unpackZ(long packed) { + return extractSigned(packed, 26, 26); + } + + public static int unpackY(long packed) { + return extractSigned(packed, 26 + 26, 12); + } + + public static int extractSigned(long i, int shift, int bits) { + return fixSign((int) (i >> shift) & mask(bits), bits); + } + + public static int fixSign(int i, int bits) { + // Using https://stackoverflow.com/a/29266331/436524 + return i << (32 - bits) >> (32 - bits); + } + + private BitMath() { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java index e8192a128..ec1aaf1d8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/BlockVector3.java @@ -24,6 +24,10 @@ import com.sk89q.worldedit.math.transform.AffineTransform; import java.util.Comparator; import static com.google.common.base.Preconditions.checkArgument; +import static com.sk89q.worldedit.math.BitMath.mask; +import static com.sk89q.worldedit.math.BitMath.unpackX; +import static com.sk89q.worldedit.math.BitMath.unpackY; +import static com.sk89q.worldedit.math.BitMath.unpackZ; /** * An immutable 3-dimensional vector. @@ -61,6 +65,31 @@ public final class BlockVector3 { return new BlockVector3(x, y, z); } + private static final int WORLD_XZ_MINMAX = 30_000_000; + private static final int WORLD_Y_MAX = 4095; + + private static boolean isHorizontallyInBounds(int h) { + return -WORLD_XZ_MINMAX <= h && h <= WORLD_XZ_MINMAX; + } + + public static boolean isLongPackable(BlockVector3 location) { + return isHorizontallyInBounds(location.getX()) && + isHorizontallyInBounds(location.getZ()) && + 0 <= location.getY() && location.getY() <= WORLD_Y_MAX; + } + + public static void checkLongPackable(BlockVector3 location) { + checkArgument(isLongPackable(location), + "Location exceeds long packing limits: %s", location); + } + + private static final long BITS_26 = mask(26); + private static final long BITS_12 = mask(12); + + public static BlockVector3 fromLongPackedForm(long packed) { + return at(unpackX(packed), unpackY(packed), unpackZ(packed)); + } + // thread-safe initialization idiom private static final class YzxOrderComparator { private static final Comparator YZX_ORDER = @@ -94,6 +123,11 @@ public final class BlockVector3 { this.z = z; } + public long toLongPackedForm() { + checkLongPackable(this); + return (x & BITS_26) | ((z & BITS_26) << 26) | (((y & (long) BITS_12) << (26 + 26))); + } + /** * Get the X coordinate. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/RegionOptimizedChunkComparator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/RegionOptimizedChunkComparator.java new file mode 100644 index 000000000..d6d2d89d6 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/RegionOptimizedChunkComparator.java @@ -0,0 +1,41 @@ +/* + * 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.math; + +import java.util.Comparator; + +import static com.sk89q.worldedit.math.BlockVector2.COMPARING_GRID_ARRANGEMENT; + +/** + * Sort block positions by region, then chunk. + */ +public class RegionOptimizedChunkComparator { + + private static final Comparator CHUNK_COMPARATOR = + Comparator.comparing((BlockVector2 chunkPos) -> chunkPos.shr(5), COMPARING_GRID_ARRANGEMENT) + .thenComparing(COMPARING_GRID_ARRANGEMENT); + + public static final Comparator INSTANCE + = Comparator.comparing(blockPos -> blockPos.toBlockVector2().shr(4), CHUNK_COMPARATOR); + + private RegionOptimizedChunkComparator() { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/RegionOptimizedComparator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/RegionOptimizedComparator.java new file mode 100644 index 000000000..ed715d703 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/RegionOptimizedComparator.java @@ -0,0 +1,36 @@ +/* + * 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.math; + +import java.util.Comparator; + +/** + * Sort block positions by region, chunk, and finally Y-Z-X. + */ +public class RegionOptimizedComparator { + + public static final Comparator INSTANCE + = RegionOptimizedChunkComparator.INSTANCE + .thenComparing(BlockVector3.sortByCoordsYzx()); + + private RegionOptimizedComparator() { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java index 766d7d99c..7953c4d31 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/PropertiesConfiguration.java @@ -118,6 +118,7 @@ public class PropertiesConfiguration extends LocalConfiguration { butcherMaxRadius = getInt("butcher-max-radius", butcherMaxRadius); allowSymlinks = getBool("allow-symbolic-links", allowSymlinks); serverSideCUI = getBool("server-side-cui", serverSideCUI); + extendedYLimit = getBool("extended-y-limit", extendedYLimit); LocalSession.MAX_HISTORY_SIZE = Math.max(15, getInt("history-size", 15)); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java index 5347eae97..be676b132 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/YAMLConfiguration.java @@ -124,6 +124,7 @@ public class YAMLConfiguration extends LocalConfiguration { String type = config.getString("shell-save-type", "").trim(); shellSaveType = type.isEmpty() ? null : type; + extendedYLimit = config.getBoolean("compat.extended-y-limit", false); } public void unload() { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java new file mode 100644 index 000000000..2620a906e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/BlockMap.java @@ -0,0 +1,427 @@ +/* + * 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.util.collection; + +import com.google.common.collect.AbstractIterator; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectIterator; + +import java.util.AbstractCollection; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static com.sk89q.worldedit.math.BitMath.fixSign; +import static com.sk89q.worldedit.math.BitMath.mask; + +/** + * A space-efficient map implementation for block locations. + */ +public class BlockMap extends AbstractMap { + + /* ========================= + IF YOU MAKE CHANGES TO THIS CLASS + Re-run BlockMapTest with the blockmap.fulltesting=true system property. + Or just temporarily remove the annotation disabling the related tests. + ========================= */ + + public static BlockMap create() { + return new BlockMap(); + } + + public static BlockMap copyOf(Map source) { + return new BlockMap(source); + } + + /* + * Stores blocks by sub-dividing them into smaller groups. + * A block location is 26 bits long for x + z, and usually + * 8 bits for y, although mods such as cubic chunks may + * expand this to infinite. We support up to 32 bits of y. + * + * Grouping key stores 20 bits x + z, 24 bits y. + * Inner key stores 6 bits x + z, 8 bits y. + * Order (lowest to highest) is x-z-y. + */ + + private static final long BITS_24 = mask(24); + private static final long BITS_20 = mask(20); + private static final int BITS_8 = mask(8); + private static final int BITS_6 = mask(6); + + private static long toGroupKey(BlockVector3 location) { + return ((location.getX() >>> 6) & BITS_20) + | (((location.getZ() >>> 6) & BITS_20) << 20) + | (((location.getY() >>> 8) & BITS_24) << (20 + 20)); + } + + private static int toInnerKey(BlockVector3 location) { + return (location.getX() & BITS_6) + | ((location.getZ() & BITS_6) << 6) + | ((location.getY() & BITS_8) << (6 + 6)); + } + + private static final long GROUP_X = BITS_20; + private static final long GROUP_Z = BITS_20 << 20; + private static final long GROUP_Y = BITS_24 << (20 + 20); + private static final int INNER_X = BITS_6; + private static final int INNER_Z = BITS_6 << 6; + private static final int INNER_Y = BITS_8 << (6 + 6); + + private static BlockVector3 reconstructLocation(long group, int inner) { + int groupX = (int) ((group & GROUP_X) << 6); + int x = fixSign(groupX | (inner & INNER_X), 26); + int groupZ = (int) ((group & GROUP_Z) >>> (20 - 6)); + int z = fixSign(groupZ | ((inner & INNER_Z) >>> 6), 26); + int groupY = (int) ((group & GROUP_Y) >>> (20 + 20 - 8)); + int y = groupY | ((inner & INNER_Y) >>> (6 + 6)); + return BlockVector3.at(x, y, z); + } + + private final Long2ObjectMap maps = new Long2ObjectOpenHashMap<>(4, 1f); + private Set> entrySet; + private Collection values; + + private BlockMap() { + } + + private BlockMap(Map source) { + putAll(source); + } + + private SubBlockMap getOrCreateMap(long groupKey) { + return maps.computeIfAbsent(groupKey, k -> new SubBlockMap()); + } + + private SubBlockMap getOrEmptyMap(long groupKey) { + return maps.getOrDefault(groupKey, SubBlockMap.EMPTY); + } + + /** + * Apply the function the the map at {@code groupKey}, and if the function empties the map, + * delete it from {@code maps}. + */ + private R cleanlyModifyMap(long groupKey, Function, R> func) { + SubBlockMap map = maps.get(groupKey); + if (map != null) { + R result = func.apply(map); + if (map.isEmpty()) { + maps.remove(groupKey); + } + return result; + } + map = new SubBlockMap(); + R result = func.apply(map); + if (!map.isEmpty()) { + maps.put(groupKey, map); + } + return result; + } + + @Override + public BaseBlock put(BlockVector3 key, BaseBlock value) { + return getOrCreateMap(toGroupKey(key)).put(toInnerKey(key), value); + } + + @Override + public BaseBlock getOrDefault(Object key, BaseBlock defaultValue) { + BlockVector3 vec = (BlockVector3) key; + return getOrEmptyMap(toGroupKey(vec)) + .getOrDefault(toInnerKey(vec), defaultValue); + } + + @Override + public void forEach(BiConsumer action) { + maps.forEach((groupKey, m) -> + m.forEach((innerKey, block) -> + action.accept(reconstructLocation(groupKey, innerKey), block) + ) + ); + } + + @Override + public void replaceAll(BiFunction function) { + maps.forEach((groupKey, m) -> + m.replaceAll((innerKey, block) -> + function.apply(reconstructLocation(groupKey, innerKey), block) + ) + ); + } + + @Override + public BaseBlock putIfAbsent(BlockVector3 key, BaseBlock value) { + return getOrCreateMap(toGroupKey(key)).putIfAbsent(toInnerKey(key), value); + } + + @Override + public boolean remove(Object key, Object value) { + BlockVector3 vec = (BlockVector3) key; + return cleanlyModifyMap(toGroupKey(vec), + map -> map.remove(toInnerKey(vec), value)); + } + + @Override + public boolean replace(BlockVector3 key, BaseBlock oldValue, BaseBlock newValue) { + return cleanlyModifyMap(toGroupKey(key), + map -> map.replace(toInnerKey(key), oldValue, newValue)); + } + + @Override + public BaseBlock replace(BlockVector3 key, BaseBlock value) { + return getOrCreateMap(toGroupKey(key)).replace(toInnerKey(key), value); + } + + @Override + public BaseBlock computeIfAbsent(BlockVector3 key, Function mappingFunction) { + return cleanlyModifyMap(toGroupKey(key), + map -> map.computeIfAbsent(toInnerKey(key), ik -> mappingFunction.apply(key))); + } + + @Override + public BaseBlock computeIfPresent(BlockVector3 key, BiFunction remappingFunction) { + return cleanlyModifyMap(toGroupKey(key), + map -> map.computeIfPresent(toInnerKey(key), (ik, block) -> remappingFunction.apply(key, block))); + } + + @Override + public BaseBlock compute(BlockVector3 key, BiFunction remappingFunction) { + return cleanlyModifyMap(toGroupKey(key), + map -> map.compute(toInnerKey(key), (ik, block) -> remappingFunction.apply(key, block))); + } + + @Override + public BaseBlock merge(BlockVector3 key, BaseBlock value, BiFunction remappingFunction) { + return cleanlyModifyMap(toGroupKey(key), + map -> map.merge(toInnerKey(key), value, remappingFunction)); + } + + @Override + public Set> entrySet() { + Set> es = entrySet; + if (es == null) { + entrySet = es = new AbstractSet>() { + @Override + public Iterator> iterator() { + return new AbstractIterator>() { + + private final ObjectIterator> primaryIterator + = Long2ObjectMaps.fastIterator(maps); + private long currentGroupKey; + private ObjectIterator> secondaryIterator; + + @Override + protected Entry computeNext() { + if (secondaryIterator == null || !secondaryIterator.hasNext()) { + if (!primaryIterator.hasNext()) { + return endOfData(); + } + + Long2ObjectMap.Entry next = primaryIterator.next(); + currentGroupKey = next.getLongKey(); + secondaryIterator = Int2ObjectMaps.fastIterator(next.getValue()); + } + Int2ObjectMap.Entry next = secondaryIterator.next(); + return new LazyEntry(currentGroupKey, next.getIntKey(), next.getValue()); + } + }; + } + + @Override + public int size() { + return BlockMap.this.size(); + } + }; + } + return es; + } + + private final class LazyEntry implements Map.Entry { + + private final long groupKey; + private final int innerKey; + private BlockVector3 lazyKey; + private BaseBlock value; + + private LazyEntry(long groupKey, int innerKey, BaseBlock value) { + this.groupKey = groupKey; + this.innerKey = innerKey; + this.value = value; + } + + @Override + public BlockVector3 getKey() { + BlockVector3 result = lazyKey; + if (result == null) { + lazyKey = result = reconstructLocation(groupKey, innerKey); + } + return result; + } + + @Override + public BaseBlock getValue() { + return value; + } + + @Override + public BaseBlock setValue(BaseBlock value) { + this.value = value; + return getOrCreateMap(groupKey).put(innerKey, value); + } + + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry) o; + if (o instanceof LazyEntry) { + LazyEntry otherE = (LazyEntry) o; + return otherE.groupKey == groupKey + && otherE.innerKey == innerKey + && Objects.equals(value, e.getValue()); + } + return Objects.equals(getKey(), e.getKey()) && Objects.equals(value, e.getValue()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getKey()) ^ Objects.hashCode(value); + } + + @Override + public String toString() { + return getKey() + "=" + getValue(); + } + } + + @Override + public boolean containsValue(Object value) { + return maps.values().stream().anyMatch(m -> m.containsValue(value)); + } + + @Override + public boolean containsKey(Object key) { + BlockVector3 vec = (BlockVector3) key; + Map activeMap = maps.get(toGroupKey(vec)); + if (activeMap == null) { + return false; + } + return activeMap.containsKey(toInnerKey(vec)); + } + + @Override + public BaseBlock get(Object key) { + BlockVector3 vec = (BlockVector3) key; + Map activeMap = maps.get(toGroupKey(vec)); + if (activeMap == null) { + return null; + } + return activeMap.get(toInnerKey(vec)); + } + + @Override + public BaseBlock remove(Object key) { + BlockVector3 vec = (BlockVector3) key; + Map activeMap = maps.get(toGroupKey(vec)); + if (activeMap == null) { + return null; + } + BaseBlock removed = activeMap.remove(toInnerKey(vec)); + if (activeMap.isEmpty()) { + maps.remove(toGroupKey(vec)); + } + return removed; + } + + @Override + public void putAll(Map m) { + if (m instanceof BlockMap) { + // optimize insertions: + ((BlockMap) m).maps.forEach((groupKey, map) -> + getOrCreateMap(groupKey).putAll(map) + ); + } else { + super.putAll(m); + } + } + + @Override + public void clear() { + maps.clear(); + } + + @Override + public int size() { + return maps.values().stream().mapToInt(Map::size).sum(); + } + + // no keySet override, since we can't really optimize it. + // we can optimize values access though, by skipping BV construction. + + @Override + public Collection values() { + Collection vs = values; + if (vs == null) { + values = vs = new AbstractCollection() { + @Override + public Iterator iterator() { + return maps.values().stream() + .flatMap(m -> m.values().stream()) + .iterator(); + } + + @Override + public int size() { + return BlockMap.this.size(); + } + }; + } + return vs; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof BlockMap) { + // optimize by skipping entry translations: + return maps.equals(((BlockMap) o).maps); + } + return super.equals(o); + } + + // satisfy checkstyle + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java index b558a7102..e8d11d2e2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LocatedBlockList.java @@ -19,74 +19,74 @@ package com.sk89q.worldedit.util.collection; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterators; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.LocatedBlock; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import javax.annotation.Nullable; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; /** * Wrapper around a list of blocks located in the world. */ public class LocatedBlockList implements Iterable { - private final Map map = new LinkedHashMap<>(); + private final BlockMap blocks = BlockMap.create(); + private final PositionList order = PositionList.create( + WorldEdit.getInstance().getConfiguration().extendedYLimit + ); public LocatedBlockList() { } public LocatedBlockList(Collection collection) { for (LocatedBlock locatedBlock : collection) { - map.put(locatedBlock.getLocation(), locatedBlock); + add(locatedBlock.getLocation(), locatedBlock.getBlock()); } } public void add(LocatedBlock setBlockCall) { checkNotNull(setBlockCall); - map.put(setBlockCall.getLocation(), setBlockCall); + add(setBlockCall.getLocation(), setBlockCall.getBlock()); } public > void add(BlockVector3 location, B block) { - add(new LocatedBlock(location, block.toBaseBlock())); + blocks.put(location, block.toBaseBlock()); + order.add(location); } public boolean containsLocation(BlockVector3 location) { - return map.containsKey(location); + return blocks.containsKey(location); } public @Nullable BaseBlock get(BlockVector3 location) { - return map.get(location).getBlock(); + return blocks.get(location); } public int size() { - return map.size(); + return order.size(); } public void clear() { - map.clear(); + blocks.clear(); + order.clear(); } @Override public Iterator iterator() { - return map.values().iterator(); + return Iterators.transform(order.iterator(), position -> + new LocatedBlock(position, blocks.get(position))); } public Iterator reverseIterator() { - List data = new ArrayList<>(map.values()); - Collections.reverse(data); - return data.iterator(); + return Iterators.transform(order.reverseIterator(), position -> + new LocatedBlock(position, blocks.get(position))); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LongPositionList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LongPositionList.java new file mode 100644 index 000000000..8d5c0b72a --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/LongPositionList.java @@ -0,0 +1,91 @@ +/* + * 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.util.collection; + +import com.google.common.collect.AbstractIterator; +import com.sk89q.worldedit.math.BlockVector3; +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.longs.LongList; +import it.unimi.dsi.fastutil.longs.LongListIterator; + +import java.util.Iterator; +import java.util.function.Predicate; +import java.util.function.ToLongFunction; + +class LongPositionList implements PositionList { + + private final LongList delegate = new LongArrayList(); + + @Override + public BlockVector3 get(int index) { + return BlockVector3.fromLongPackedForm(delegate.getLong(index)); + } + + @Override + public void add(BlockVector3 vector) { + delegate.add(vector.toLongPackedForm()); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + public Iterator iterator() { + return new PositionIterator(delegate.iterator(), + LongListIterator::hasNext, + LongListIterator::nextLong); + } + + @Override + public Iterator reverseIterator() { + return new PositionIterator(delegate.listIterator(size()), + LongListIterator::hasPrevious, + LongListIterator::previousLong); + } + + private static final class PositionIterator extends AbstractIterator { + + private final LongListIterator iterator; + private final Predicate hasNext; + private final ToLongFunction next; + + private PositionIterator(LongListIterator iterator, + Predicate hasNext, + ToLongFunction next) { + this.iterator = iterator; + this.hasNext = hasNext; + this.next = next; + } + + @Override + protected BlockVector3 computeNext() { + return hasNext.test(iterator) + ? BlockVector3.fromLongPackedForm(next.applyAsLong(iterator)) + : endOfData(); + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/PositionList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/PositionList.java new file mode 100644 index 000000000..793f0fef3 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/PositionList.java @@ -0,0 +1,47 @@ +/* + * 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.util.collection; + +import com.sk89q.worldedit.math.BlockVector3; + +import java.util.Iterator; + +interface PositionList { + + static PositionList create(boolean extendedYLimit) { + if (extendedYLimit) { + return new VectorPositionList(); + } + return new LongPositionList(); + } + + BlockVector3 get(int index); + + void add(BlockVector3 vector); + + int size(); + + void clear(); + + Iterator iterator(); + + Iterator reverseIterator(); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/SubBlockMap.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/SubBlockMap.java new file mode 100644 index 000000000..440f52eee --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/SubBlockMap.java @@ -0,0 +1,194 @@ +/* + * 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.util.collection; + +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import it.unimi.dsi.fastutil.ints.AbstractInt2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntMaps; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.AbstractObjectSet; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectSet; + +import java.util.NoSuchElementException; +import java.util.function.BiFunction; + +/** + * Int-to-BaseBlock map, but with optimizations for common cases. + */ +class SubBlockMap extends AbstractInt2ObjectMap { + + private static boolean hasInt(BlockState b) { + return BlockStateIdAccess.getBlockStateId(b).isPresent(); + } + + private static boolean isUncommon(BaseBlock block) { + return block.hasNbtData() || !hasInt(block.toImmutableState()); + } + + private static int assumeAsInt(BlockState b) { + return BlockStateIdAccess.getBlockStateId(b) + .orElseThrow(() -> new IllegalStateException("Block state " + b + " did not have an ID")); + } + + private static BaseBlock assumeAsBlock(int id) { + if (id == Integer.MIN_VALUE) { + return null; + } + BlockState state = BlockStateIdAccess.getBlockStateById(id); + if (state == null) { + throw new IllegalStateException("No state for ID " + id); + } + return state.toBaseBlock(); + } + + static final SubBlockMap EMPTY = new SubBlockMap(); + + private final Int2IntMap commonMap = new Int2IntOpenHashMap(64, 1f); + private final Int2ObjectMap uncommonMap = new Int2ObjectOpenHashMap<>(1, 1f); + + { + commonMap.defaultReturnValue(Integer.MIN_VALUE); + } + + @Override + public int size() { + return commonMap.size() + uncommonMap.size(); + } + + @Override + public ObjectSet> int2ObjectEntrySet() { + return new AbstractObjectSet>() { + @Override + public ObjectIterator> iterator() { + return new ObjectIterator>() { + + private final ObjectIterator commonIter + = Int2IntMaps.fastIterator(commonMap); + private final ObjectIterator> uncommonIter + = Int2ObjectMaps.fastIterator(uncommonMap); + + @Override + public boolean hasNext() { + return commonIter.hasNext() || uncommonIter.hasNext(); + } + + @Override + public Entry next() { + if (commonIter.hasNext()) { + Int2IntMap.Entry e = commonIter.next(); + return new BasicEntry<>( + e.getIntKey(), assumeAsBlock(e.getIntValue()) + ); + } + if (uncommonIter.hasNext()) { + return uncommonIter.next(); + } + throw new NoSuchElementException(); + } + }; + } + + @Override + public int size() { + return SubBlockMap.this.size(); + } + }; + } + + @Override + public BaseBlock get(int key) { + int oldId = commonMap.get(key); + if (oldId == Integer.MIN_VALUE) { + return uncommonMap.get(key); + } + return assumeAsBlock(oldId); + } + + @Override + public boolean containsKey(int k) { + return commonMap.containsKey(k) || uncommonMap.containsKey(k); + } + + @Override + public boolean containsValue(Object v) { + BaseBlock block = (BaseBlock) v; + if (isUncommon(block)) { + return uncommonMap.containsValue(block); + } + return commonMap.containsValue(assumeAsInt(block.toImmutableState())); + } + + @Override + public BaseBlock put(int key, BaseBlock value) { + if (isUncommon(value)) { + BaseBlock old = uncommonMap.put(key, value); + if (old == null) { + // ensure common doesn't have the entry too + int oldId = commonMap.remove(key); + return assumeAsBlock(oldId); + } + return old; + } + int oldId = commonMap.put(key, assumeAsInt(value.toImmutableState())); + return assumeAsBlock(oldId); + } + + @Override + public BaseBlock remove(int key) { + int removed = commonMap.remove(key); + if (removed == Integer.MIN_VALUE) { + return uncommonMap.remove(key); + } + return assumeAsBlock(removed); + } + + @Override + public void replaceAll(BiFunction function) { + for (ObjectIterator iter = Int2IntMaps.fastIterator(commonMap); + iter.hasNext(); ) { + Int2IntMap.Entry next = iter.next(); + BaseBlock value = function.apply(next.getIntKey(), assumeAsBlock(next.getIntValue())); + if (isUncommon(value)) { + uncommonMap.put(next.getIntKey(), value); + iter.remove(); + } else { + next.setValue(assumeAsInt(value.toImmutableState())); + } + } + for (ObjectIterator> iter = Int2ObjectMaps.fastIterator(uncommonMap); + iter.hasNext(); ) { + Int2ObjectMap.Entry next = iter.next(); + BaseBlock value = function.apply(next.getIntKey(), next.getValue()); + if (isUncommon(value)) { + next.setValue(value); + } else { + commonMap.put(next.getIntKey(), assumeAsInt(value.toImmutableState())); + iter.remove(); + } + } + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java new file mode 100644 index 000000000..6c8d27ddf --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/collection/VectorPositionList.java @@ -0,0 +1,98 @@ +/* + * 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.util.collection; + +import com.google.common.collect.AbstractIterator; +import com.sk89q.worldedit.math.BlockVector3; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntIterator; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.ints.IntListIterator; + +import java.util.Iterator; + +class VectorPositionList implements PositionList { + + private final IntList delegate = new IntArrayList(); + + @Override + public BlockVector3 get(int index) { + int ri = index * 3; + return BlockVector3.at( + delegate.getInt(ri), + delegate.getInt(ri + 1), + delegate.getInt(ri + 2)); + } + + @Override + public void add(BlockVector3 vector) { + delegate.add(vector.getX()); + delegate.add(vector.getY()); + delegate.add(vector.getZ()); + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + public Iterator iterator() { + return new AbstractIterator() { + + private final IntIterator iterator = delegate.iterator(); + + @Override + protected BlockVector3 computeNext() { + if (!iterator.hasNext()) { + return endOfData(); + } + return BlockVector3.at( + iterator.nextInt(), + iterator.nextInt(), + iterator.nextInt()); + } + }; + } + + @Override + public Iterator reverseIterator() { + return new AbstractIterator() { + + private final IntListIterator iterator = delegate.listIterator(delegate.size()); + + @Override + protected BlockVector3 computeNext() { + if (!iterator.hasPrevious()) { + return endOfData(); + } + return BlockVector3.at( + iterator.previousInt(), + iterator.previousInt(), + iterator.previousInt()); + } + }; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/concurrency/LazyReference.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/concurrency/LazyReference.java new file mode 100644 index 000000000..720ca0161 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/concurrency/LazyReference.java @@ -0,0 +1,75 @@ +/* + * 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.util.concurrency; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Supplier; + +/** + * Thread-safe lazy reference. + */ +public class LazyReference { + + public static LazyReference from(Supplier valueComputation) { + return new LazyReference<>(valueComputation); + } + + // Memory saving technique: hold the computation info in the same reference field that we'll + // put the value into, so the memory possibly retained by those parts is GC'able as soon as + // it's no longer needed. + + private static final class RefInfo { + private final Lock lock = new ReentrantLock(); + private final Supplier valueComputation; + + private RefInfo(Supplier valueComputation) { + this.valueComputation = valueComputation; + } + } + + private Object value; + + private LazyReference(Supplier valueComputation) { + this.value = new RefInfo<>(valueComputation); + } + + // casts are safe, value is either RefInfo or T + @SuppressWarnings("unchecked") + public T getValue() { + Object v = value; + if (!(v instanceof RefInfo)) { + return (T) v; + } + RefInfo refInfo = (RefInfo) v; + refInfo.lock.lock(); + try { + v = value; + if (!(v instanceof RefInfo)) { + return (T) v; + } + value = v = refInfo.valueComputation.get(); + return (T) v; + } finally { + refInfo.lock.unlock(); + } + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index 34ffee81c..9cd5435f7 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -26,9 +26,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Table; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.registry.state.Property; -import com.sk89q.worldedit.world.registry.BlockRegistry; import java.util.Collections; import java.util.Comparator; @@ -60,7 +58,6 @@ public class BlockState implements BlockStateHolder { } static Map, Object>, BlockState> generateStateMap(BlockType blockType) { - BlockRegistry registry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.WORLD_EDITING).getRegistries().getBlockRegistry(); Map, Object>, BlockState> stateMap = new LinkedHashMap<>(); List> properties = blockType.getProperties(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java index e86ee7e83..66f286ca5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockType.java @@ -19,28 +19,26 @@ package com.sk89q.worldedit.world.block; -import static com.google.common.base.Preconditions.checkArgument; - import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.LegacyMapper; -import java.util.ArrayList; +import javax.annotation.Nullable; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; -import java.util.function.Supplier; -import javax.annotation.Nullable; +import static com.google.common.base.Preconditions.checkArgument; public class BlockType implements Keyed { @@ -48,11 +46,18 @@ public class BlockType implements Keyed { private final String id; private final Function values; - private final AtomicReference defaultState = new AtomicReference<>(); - private final AtomicReference emptyFuzzy = new AtomicReference<>(); - private final AtomicReference>> properties = new AtomicReference<>(); - private final AtomicReference blockMaterial = new AtomicReference<>(); - private final AtomicReference, Object>, BlockState>> blockStatesMap = new AtomicReference<>(); + private final LazyReference defaultState + = LazyReference.from(this::computeDefaultState); + private final LazyReference emptyFuzzy + = LazyReference.from(() -> new FuzzyBlockState(this)); + private final LazyReference>> properties + = LazyReference.from(() -> ImmutableMap.copyOf(WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getProperties(this))); + private final LazyReference blockMaterial + = LazyReference.from(() -> WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getMaterial(this)); + private final LazyReference, Object>, BlockState>> blockStatesMap + = LazyReference.from(() -> BlockState.generateStateMap(this)); public BlockType(String id) { this(id, null); @@ -67,24 +72,16 @@ public class BlockType implements Keyed { this.values = values; } - private T updateField(AtomicReference field, Supplier value) { - T result = field.get(); - if (result == null) { - // swap in new value, if someone doesn't beat us - T update = value.get(); - if (field.compareAndSet(null, update)) { - // use ours - result = update; - } else { - // update to real value - result = field.get(); - } + private BlockState computeDefaultState() { + BlockState defaultState = Iterables.getFirst(getBlockStatesMap().values(), null); + if (values != null) { + defaultState = values.apply(defaultState); } - return result; + return defaultState; } private Map, Object>, BlockState> getBlockStatesMap() { - return updateField(blockStatesMap, () -> BlockState.generateStateMap(this)); + return blockStatesMap.getValue(); } /** @@ -117,8 +114,7 @@ public class BlockType implements Keyed { * @return The properties map */ public Map> getPropertyMap() { - return updateField(properties, () -> ImmutableMap.copyOf(WorldEdit.getInstance().getPlatformManager() - .queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getProperties(this))); + return properties.getValue(); } /** @@ -150,17 +146,11 @@ public class BlockType implements Keyed { * @return The default state */ public BlockState getDefaultState() { - return updateField(defaultState, () -> { - BlockState defaultState = new ArrayList<>(getBlockStatesMap().values()).get(0); - if (values != null) { - defaultState = values.apply(defaultState); - } - return defaultState; - }); + return defaultState.getValue(); } public FuzzyBlockState getFuzzyMatcher() { - return updateField(emptyFuzzy, () -> new FuzzyBlockState(this)); + return emptyFuzzy.getValue(); } /** @@ -208,8 +198,7 @@ public class BlockType implements Keyed { * @return The material */ public BlockMaterial getMaterial() { - return updateField(blockMaterial, () -> WorldEdit.getInstance().getPlatformManager() - .queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getMaterial(this)); + return blockMaterial.getValue(); } /** diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java index d26d955d0..de9cce3cc 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java @@ -27,9 +27,9 @@ import com.sk89q.worldedit.internal.expression.parser.ParserException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import static java.lang.Math.atan2; import static java.lang.Math.sin; @@ -37,12 +37,16 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class ExpressionTest { + + private Platform mockPlat = mock(Platform.class); + @BeforeEach public void setup() { - Platform mockPlat = Mockito.mock(Platform.class); - Mockito.when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() { + when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() { @Override public void load() { } @@ -50,6 +54,11 @@ public class ExpressionTest { WorldEdit.getInstance().getPlatformManager().register(mockPlat); } + @AfterEach + public void tearDown() { + WorldEdit.getInstance().getPlatformManager().unregister(mockPlat); + } + @Test public void testEvaluate() throws ExpressionException { // check diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/util/VariedVectorsProvider.java b/worldedit-core/src/test/java/com/sk89q/worldedit/util/VariedVectorsProvider.java new file mode 100644 index 000000000..10a835392 --- /dev/null +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/util/VariedVectorsProvider.java @@ -0,0 +1,133 @@ +/* + * 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.util; + +import com.google.common.collect.AbstractIterator; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Streams; +import com.sk89q.worldedit.math.BlockVector3; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.junit.jupiter.params.support.AnnotationConsumer; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Iterator; +import java.util.Set; +import java.util.stream.Stream; + +/** + * Argument provider for various vectors. + */ +public final class VariedVectorsProvider implements ArgumentsProvider, AnnotationConsumer { + + @Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD }) + @Retention(RetentionPolicy.RUNTIME) + @Documented + @ArgumentsSource(VariedVectorsProvider.class) + @ParameterizedTest(name = ParameterizedTest.ARGUMENTS_PLACEHOLDER) + public @interface Test { + + /** + * If {@code true}, provide a non-matching vector from + * the existing vectors set as well. This will nearly + * square the number of tests executed, since it will + * test every non-matching vector. + */ + boolean provideNonMatching() default false; + + } + + private static final int WORLD_XZ_MINMAX = 30_000_000; + private static final long WORLD_Y_MAX = Integer.MAX_VALUE; + private static final long WORLD_Y_MIN = Integer.MIN_VALUE; + + // For better coverage assurance, increase these values for a local Gradle run. + // Don't do it for IntelliJ, it'll probably run out of memory. + private static final int DIVISIONS_XZ = Integer.getInteger("variedvecs.divisions.xz", 5); + private static final int DIVISIONS_Y = Integer.getInteger("variedvecs.divisions.y", 5); + + private static final int XZ_STEP = (WORLD_XZ_MINMAX * 2) / DIVISIONS_XZ; + private static final long Y_STEP = (WORLD_Y_MAX * 2) / DIVISIONS_Y; + + private static final Set ALWAYS_INCLUDE = + ImmutableSet.of(BlockVector3.ZERO, BlockVector3.ONE, + BlockVector3.at(-WORLD_XZ_MINMAX, 0, -WORLD_XZ_MINMAX), + BlockVector3.at(WORLD_XZ_MINMAX, 0, WORLD_XZ_MINMAX), + BlockVector3.at(-WORLD_XZ_MINMAX, WORLD_Y_MAX, -WORLD_XZ_MINMAX), + BlockVector3.at(WORLD_XZ_MINMAX, WORLD_Y_MAX, WORLD_XZ_MINMAX)); + + private boolean provideNonMatching; + + @Override + public void accept(Test test) { + provideNonMatching = test.provideNonMatching(); + } + + @Override + public Stream provideArguments(ExtensionContext context) { + if (provideNonMatching) { + return makeVectorsStream() + .flatMap(vec -> makeVectorsStream().filter(v -> !v.equals(vec)) + .map(v -> Arguments.of(vec, v))); + } + return makeVectorsStream().map(Arguments::of); + } + + public static Stream makeVectorsStream() { + return Stream.concat( + ALWAYS_INCLUDE.stream(), + Streams.stream(generateVectors()).filter(v -> !ALWAYS_INCLUDE.contains(v)) + ); + } + + private static Iterator generateVectors() { + return new AbstractIterator() { + + private int x = -WORLD_XZ_MINMAX + 1; + private int z = -WORLD_XZ_MINMAX + 1; + private long y = WORLD_Y_MAX; + + @Override + protected BlockVector3 computeNext() { + if (x > WORLD_XZ_MINMAX) { + return endOfData(); + } + BlockVector3 newVector = BlockVector3.at(x, (int) y, z); + y += Y_STEP; + if (y > WORLD_Y_MAX) { + y = 0; + z += XZ_STEP; + if (z > WORLD_XZ_MINMAX) { + z = -WORLD_XZ_MINMAX; + x += XZ_STEP; + } + } + return newVector; + } + }; + } +} diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/util/collection/BlockMapTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/util/collection/BlockMapTest.java new file mode 100644 index 000000000..64b18c84e --- /dev/null +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/util/collection/BlockMapTest.java @@ -0,0 +1,588 @@ +/* + * 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.util.collection; + +import com.google.common.collect.ImmutableMap; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.PlatformManager; +import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.registry.Registry; +import com.sk89q.worldedit.util.VariedVectorsProvider; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.registry.BundledRegistries; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.lang.reflect.Field; +import java.util.AbstractMap; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +@DisplayName("An ordered block map") +class BlockMapTest { + + private static Platform mockedPlatform = mock(Platform.class); + + @BeforeAll + static void setupFakePlatform() { + when(mockedPlatform.getRegistries()).thenReturn(new BundledRegistries() { + }); + when(mockedPlatform.getCapabilities()).thenReturn(ImmutableMap.of( + Capability.WORLD_EDITING, Preference.PREFERRED, + Capability.GAME_HOOKS, Preference.PREFERRED + )); + PlatformManager platformManager = WorldEdit.getInstance().getPlatformManager(); + platformManager.register(mockedPlatform); + + registerBlock("minecraft:air"); + registerBlock("minecraft:oak_wood"); + } + + @AfterAll + static void tearDownFakePlatform() throws Exception { + WorldEdit.getInstance().getPlatformManager().unregister(mockedPlatform); + Field map = Registry.class.getDeclaredField("map"); + map.setAccessible(true); + ((Map) map.get(BlockType.REGISTRY)).clear(); + } + + private static void registerBlock(String id) { + BlockType.REGISTRY.register(id, new BlockType(id)); + } + + @Mock + private Function function; + @Mock + private BiFunction biFunction; + @Mock + private BiFunction mergeFunction; + @Mock + private BiConsumer biConsumer; + + private final BaseBlock air = checkNotNull(BlockTypes.AIR).getDefaultState().toBaseBlock(); + private final BaseBlock oakWood = checkNotNull(BlockTypes.OAK_WOOD).getDefaultState().toBaseBlock(); + + private BlockMap map = BlockMap.create(); + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + } + + @AfterEach + void tearDown() { + map.clear(); + } + + @Test + @DisplayName("throws ClassCastException if invalid argument to get") + void throwsFromGetOnInvalidArgument() { + assertThrows(ClassCastException.class, () -> map.get("")); + } + + @Nested + @DisplayName("when created") + class WhenCreated { + + @Test + @DisplayName("is empty") + void isEmpty() { + assertEquals(0, map.size()); + } + + @Test + @DisplayName("is equal to another empty map") + void isEqualToEmptyMap() { + assertEquals(ImmutableMap.of(), map); + } + + @Test + @DisplayName("has the same hashCode as another empty map") + void isHashCodeEqualToEmptyMap() { + assertEquals(ImmutableMap.of().hashCode(), map.hashCode()); + } + + @Test + @DisplayName("returns `null` from get") + void returnsNullFromGet() { + assertNull(map.get(BlockVector3.ZERO)); + } + + @Test + @DisplayName("contains no keys") + void containsNoKeys() { + assertEquals(0, map.keySet().size()); + assertFalse(map.containsKey(BlockVector3.ZERO)); + } + + @Test + @DisplayName("contains no values") + void containsNoValues() { + assertEquals(0, map.values().size()); + assertFalse(map.containsValue(air)); + } + + @Test + @DisplayName("contains no entries") + void containsNoEntries() { + assertEquals(0, map.entrySet().size()); + } + + @Test + @DisplayName("returns the default value from getOrDefault") + void returnsDefaultFromGetOrDefault() { + assertEquals(air, map.getOrDefault(BlockVector3.ZERO, air)); + } + + @Test + @DisplayName("never calls the forEach action") + void neverCallsForEachAction() { + map.forEach(biConsumer); + verifyZeroInteractions(biConsumer); + } + + @Test + @DisplayName("never calls the replaceAll function") + void neverCallsReplaceAllFunction() { + map.replaceAll(biFunction); + verifyZeroInteractions(biFunction); + } + + @Test + @DisplayName("inserts on putIfAbsent") + void insertOnPutIfAbsent() { + assertNull(map.putIfAbsent(BlockVector3.ZERO, air)); + assertEquals(1, map.size()); + assertEquals(air, map.get(BlockVector3.ZERO)); + } + + @Test + @DisplayName("remove(key) returns null") + void removeKeyReturnsNull() { + assertNull(map.remove(BlockVector3.ZERO)); + } + + @Test + @DisplayName("remove(key, value) returns false") + void removeKeyValueReturnsFalse() { + assertFalse(map.remove(BlockVector3.ZERO, air)); + } + + @Test + @DisplayName("does nothing on replace") + void doesNothingOnReplace() { + assertNull(map.replace(BlockVector3.ZERO, air)); + assertEquals(0, map.size()); + assertFalse(map.replace(BlockVector3.ZERO, null, air)); + assertEquals(0, map.size()); + } + + @Test + @DisplayName("inserts on computeIfAbsent") + void insertOnComputeIfAbsent() { + assertEquals(air, map.computeIfAbsent(BlockVector3.ZERO, k -> air)); + assertEquals(1, map.size()); + assertEquals(air, map.get(BlockVector3.ZERO)); + } + + @Test + @DisplayName("inserts on compute") + void insertOnCompute() { + assertEquals(air, map.compute(BlockVector3.ZERO, (k, v) -> air)); + assertEquals(1, map.size()); + assertEquals(air, map.get(BlockVector3.ZERO)); + } + + @Test + @DisplayName("does nothing on computeIfPresent") + void doesNothingOnComputeIfPresent() { + assertNull(map.computeIfPresent(BlockVector3.ZERO, (k, v) -> air)); + assertEquals(0, map.size()); + } + + @Test + @DisplayName("inserts on merge, without calling merge function") + void insertsOnMerge() { + assertEquals(air, map.merge(BlockVector3.ZERO, air, mergeFunction)); + assertEquals(1, map.size()); + assertEquals(air, map.get(BlockVector3.ZERO)); + verifyZeroInteractions(mergeFunction); + } + + } + + @Nested + @DisplayName("after having an entry added") + @EnabledIfSystemProperty(named = "blockmap.fulltesting", matches = "true") + class AfterEntryAdded { + + // Note: This section of tests would really benefit from + // being able to parameterize classes. It's not part of JUnit + // yet though: https://github.com/junit-team/junit5/issues/878 + + @VariedVectorsProvider.Test + @DisplayName("has a size of one") + void hasSizeOne(BlockVector3 vec) { + map.put(vec, air); + assertEquals(1, map.size()); + } + + @VariedVectorsProvider.Test + @DisplayName("is equal to another map with the same entry") + void isEqualToSimilarMap(BlockVector3 vec) { + map.put(vec, air); + assertEquals(ImmutableMap.of(vec, air), map); + } + + @VariedVectorsProvider.Test(provideNonMatching = true) + @DisplayName("is not equal to another map with a different key") + void isNotEqualToDifferentKeyMap(BlockVector3 vec, BlockVector3 nonMatch) { + map.put(vec, air); + assertNotEquals(ImmutableMap.of(nonMatch, air), map); + } + + @VariedVectorsProvider.Test + @DisplayName("is not equal to another map with a different value") + void isNotEqualToDifferentValueMap(BlockVector3 vec) { + map.put(vec, air); + assertNotEquals(ImmutableMap.of(vec, oakWood), map); + } + + @VariedVectorsProvider.Test + @DisplayName("is not equal to an empty map") + void isNotEqualToEmptyMap(BlockVector3 vec) { + map.put(vec, air); + assertNotEquals(ImmutableMap.of(), map); + } + + @VariedVectorsProvider.Test + @DisplayName("has the same hashCode as another map with the same entry") + void isHashCodeEqualToSimilarMap(BlockVector3 vec) { + map.put(vec, air); + assertEquals(ImmutableMap.of(vec, air).hashCode(), map.hashCode()); + } + + @VariedVectorsProvider.Test(provideNonMatching = true) + @DisplayName("has a different hashCode from another map with a different key") + void isHashCodeNotEqualToDifferentKeyMap(BlockVector3 vec, BlockVector3 nonMatch) { + assumeFalse(vec.hashCode() == nonMatch.hashCode(), + "Vectors have equivalent hashCodes, maps will too."); + map.put(vec, air); + assertNotEquals(ImmutableMap.of(nonMatch, air).hashCode(), map.hashCode()); + } + + @VariedVectorsProvider.Test + @DisplayName("has a different hashCode from another map with a different value") + void isHashCodeNotEqualToDifferentValueMap(BlockVector3 vec) { + map.put(vec, air); + assertNotEquals(ImmutableMap.of(vec, oakWood).hashCode(), map.hashCode()); + } + + @VariedVectorsProvider.Test + @DisplayName("has a different hashCode from an empty map") + void isHashCodeNotEqualToEmptyMap(BlockVector3 vec) { + map.put(vec, air); + assertNotEquals(ImmutableMap.of().hashCode(), map.hashCode()); + } + + @VariedVectorsProvider.Test + @DisplayName("returns value from get") + void returnsValueFromGet(BlockVector3 vec) { + map.put(vec, air); + assertEquals(air, map.get(vec)); + } + + @VariedVectorsProvider.Test(provideNonMatching = true) + @DisplayName("returns `null` from get with different key") + void returnsValueFromGet(BlockVector3 vec, BlockVector3 nonMatch) { + map.put(vec, air); + assertNotEquals(air, map.get(nonMatch)); + } + + @VariedVectorsProvider.Test + @DisplayName("contains the key") + void containsTheKey(BlockVector3 vec) { + map.put(vec, air); + assertEquals(1, map.keySet().size()); + assertTrue(map.keySet().contains(vec)); + assertTrue(map.containsKey(vec)); + } + + @VariedVectorsProvider.Test + @DisplayName("contains the value") + void containsTheValue(BlockVector3 vec) { + map.put(vec, air); + assertEquals(1, map.values().size()); + assertTrue(map.values().contains(air)); + assertTrue(map.containsValue(air)); + } + + @VariedVectorsProvider.Test + @DisplayName("contains the entry") + void containsTheEntry(BlockVector3 vec) { + map.put(vec, air); + assertEquals(1, map.entrySet().size()); + assertEquals(new AbstractMap.SimpleImmutableEntry<>(vec, air), map.entrySet().iterator().next()); + } + + @VariedVectorsProvider.Test + @DisplayName("returns the provided value from getOrDefault") + void returnsProvidedFromGetOrDefault(BlockVector3 vec) { + map.put(vec, air); + assertEquals(air, map.getOrDefault(vec, oakWood)); + } + + @VariedVectorsProvider.Test(provideNonMatching = true) + @DisplayName("returns the default value from getOrDefault with a different key") + void returnsDefaultFromGetOrDefaultWrongKey(BlockVector3 vec, BlockVector3 nonMatch) { + map.put(vec, air); + assertEquals(oakWood, map.getOrDefault(nonMatch, oakWood)); + } + + @VariedVectorsProvider.Test + @DisplayName("calls the forEach action once") + void neverCallsForEachAction(BlockVector3 vec) { + map.put(vec, air); + map.forEach(biConsumer); + verify(biConsumer).accept(vec, air); + verifyNoMoreInteractions(biConsumer); + } + + @VariedVectorsProvider.Test + @DisplayName("replaces value using replaceAll") + void neverCallsReplaceAllFunction(BlockVector3 vec) { + map.put(vec, air); + map.replaceAll((v, b) -> oakWood); + assertEquals(oakWood, map.get(vec)); + } + + @VariedVectorsProvider.Test + @DisplayName("does not insert on `putIfAbsent`") + void noInsertOnPutIfAbsent(BlockVector3 vec) { + map.put(vec, air); + assertEquals(air, map.putIfAbsent(vec, oakWood)); + assertEquals(1, map.size()); + assertEquals(air, map.get(vec)); + } + + @VariedVectorsProvider.Test(provideNonMatching = true) + @DisplayName("inserts on `putIfAbsent` to a different key") + void insertOnPutIfAbsentDifferentKey(BlockVector3 vec, BlockVector3 nonMatch) { + map.put(vec, air); + assertNull(map.putIfAbsent(nonMatch, oakWood)); + assertEquals(2, map.size()); + assertEquals(air, map.get(vec)); + assertEquals(oakWood, map.get(nonMatch)); + } + + @VariedVectorsProvider.Test + @DisplayName("remove(key) returns the old value") + void removeKeyReturnsOldValue(BlockVector3 vec) { + map.put(vec, air); + assertEquals(air, map.remove(vec)); + assertEquals(0, map.size()); + } + + @VariedVectorsProvider.Test(provideNonMatching = true) + @DisplayName("remove(nonMatch) returns null") + void removeNonMatchingKeyReturnsNull(BlockVector3 vec, BlockVector3 nonMatch) { + map.put(vec, air); + assertNull(map.remove(nonMatch)); + assertEquals(1, map.size()); + } + + @VariedVectorsProvider.Test + @DisplayName("remove(key, value) returns true") + void removeKeyValueReturnsTrue(BlockVector3 vec) { + map.put(vec, air); + assertTrue(map.remove(vec, air)); + assertEquals(0, map.size()); + } + + @VariedVectorsProvider.Test + @DisplayName("remove(key, value) returns false for wrong value") + void removeKeyValueReturnsFalseWrongValue(BlockVector3 vec) { + map.put(vec, air); + assertFalse(map.remove(vec, oakWood)); + assertEquals(1, map.size()); + } + + @VariedVectorsProvider.Test + @DisplayName("replaces value at key") + void replacesValueAtKey(BlockVector3 vec) { + map.put(vec, air); + + assertEquals(air, map.replace(vec, oakWood)); + assertEquals(1, map.size()); + assertEquals(oakWood, map.get(vec)); + + assertTrue(map.replace(vec, oakWood, air)); + assertEquals(1, map.size()); + assertEquals(air, map.get(vec)); + } + + @VariedVectorsProvider.Test(provideNonMatching = true) + @DisplayName("does not replace value at different key") + void doesNotReplaceAtDifferentKey(BlockVector3 vec, BlockVector3 nonMatch) { + map.put(vec, air); + + assertNull(map.replace(nonMatch, oakWood)); + assertEquals(1, map.size()); + assertEquals(air, map.get(vec)); + + assertFalse(map.replace(nonMatch, air, oakWood)); + assertEquals(1, map.size()); + assertEquals(air, map.get(vec)); + } + + @VariedVectorsProvider.Test + @DisplayName("does not insert on computeIfAbsent") + void doesNotInsertComputeIfAbsent(BlockVector3 vec) { + map.put(vec, air); + assertEquals(air, map.computeIfAbsent(vec, k -> { + assertEquals(vec, k); + return oakWood; + })); + assertEquals(1, map.size()); + assertEquals(air, map.get(vec)); + } + + @VariedVectorsProvider.Test(provideNonMatching = true) + @DisplayName("inserts on computeIfAbsent with different key") + void insertsOnComputeIfAbsentDifferentKey(BlockVector3 vec, BlockVector3 nonMatch) { + map.put(vec, air); + assertEquals(oakWood, map.computeIfAbsent(nonMatch, k -> { + assertEquals(nonMatch, k); + return oakWood; + })); + assertEquals(2, map.size()); + assertEquals(air, map.get(vec)); + assertEquals(oakWood, map.get(nonMatch)); + } + + @VariedVectorsProvider.Test + @DisplayName("replaces on compute") + void replaceOnCompute(BlockVector3 vec) { + map.put(vec, air); + assertEquals(oakWood, map.compute(vec, (k, v) -> { + assertEquals(vec, k); + assertEquals(air, v); + return oakWood; + })); + assertEquals(1, map.size()); + assertEquals(oakWood, map.get(vec)); + assertNull(map.compute(vec, (k, v) -> null)); + assertEquals(0, map.size()); + } + + @VariedVectorsProvider.Test(provideNonMatching = true) + @DisplayName("inserts on compute with different key") + void insertOnComputeDifferentKey(BlockVector3 vec, BlockVector3 nonMatch) { + map.put(vec, air); + assertEquals(oakWood, map.compute(nonMatch, (k, v) -> { + assertEquals(nonMatch, k); + assertNull(v); + return oakWood; + })); + assertEquals(2, map.size()); + assertEquals(air, map.get(vec)); + assertEquals(oakWood, map.get(nonMatch)); + assertNull(map.compute(nonMatch, (k, v) -> null)); + assertEquals(1, map.size()); + assertEquals(air, map.get(vec)); + } + + @VariedVectorsProvider.Test + @DisplayName("replaces on computeIfPresent") + void replacesOnComputeIfPresent(BlockVector3 vec) { + map.put(vec, air); + assertEquals(oakWood, map.computeIfPresent(vec, (k, v) -> { + assertEquals(vec, k); + assertEquals(air, v); + return oakWood; + })); + assertEquals(1, map.size()); + assertEquals(oakWood, map.get(vec)); + assertNull(map.computeIfPresent(vec, (k, v) -> null)); + assertEquals(0, map.size()); + } + + @VariedVectorsProvider.Test + @DisplayName("inserts on merge, with call to merge function") + void insertsOnMerge(BlockVector3 vec) { + map.put(vec, air); + assertEquals(oakWood, map.merge(vec, oakWood, (o, n) -> { + assertEquals(air, o); + assertEquals(oakWood, n); + return n; + })); + assertEquals(1, map.size()); + assertEquals(oakWood, map.get(vec)); + } + + } + + @Test + @DisplayName("contains all inserted vectors") + void containsAllInsertedVectors() { + Set allVectors = VariedVectorsProvider.makeVectorsStream().collect(Collectors.toSet()); + for (BlockVector3 vec : allVectors) { + map.put(vec, air); + } + assertEquals(allVectors.size(), map.size()); + assertEquals(allVectors, map.keySet()); + for (Map.Entry entry : map.entrySet()) { + assertTrue(allVectors.contains(entry.getKey())); + assertEquals(air, entry.getValue()); + } + } + +} diff --git a/worldedit-core/src/test/resources/junit-platform.properties b/worldedit-core/src/test/resources/junit-platform.properties new file mode 100644 index 000000000..ee7c4fad3 --- /dev/null +++ b/worldedit-core/src/test/resources/junit-platform.properties @@ -0,0 +1,5 @@ +junit.jupiter.execution.parallel.enabled=true +junit.jupiter.execution.parallel.mode.default=concurrent +junit.jupiter.execution.parallel.mode.classes.default=same_thread +junit.jupiter.execution.parallel.config.strategy=dynamic +junit.jupiter.execution.parallel.config.dynamic.factor=4 diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java index a3bc382f4..377633000 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/config/ConfigurateConfiguration.java @@ -129,5 +129,7 @@ public class ConfigurateConfiguration extends LocalConfiguration { String type = node.getNode("shell-save-type").getString("").trim(); shellSaveType = type.equals("") ? null : type; + + extendedYLimit = node.getNode("compat", "extended-y-limit").getBoolean(false); } } \ No newline at end of file From 33633acbe7f3ef703027fc3ea3da0d6e8b3294e2 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 12 Aug 2019 10:04:29 -0700 Subject: [PATCH 322/366] Add validator extent to every entry point, fix extent ordering --- .../java/com/sk89q/worldedit/EditSession.java | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) 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 aff049e9a..e3bcac4b1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -184,13 +184,8 @@ public class EditSession implements Extent, AutoCloseable { private @Nullable FastModeExtent fastModeExtent; private final SurvivalModeExtent survivalExtent; private @Nullable ChunkBatchingExtent chunkBatchingExtent; - private @Nullable ChunkLoadingExtent chunkLoadingExtent; - private @Nullable LastAccessExtentCache cacheExtent; - private @Nullable BlockQuirkExtent quirkExtent; - private @Nullable DataValidatorExtent validator; private final BlockBagExtent blockBagExtent; private final MultiStageReorder reorderExtent; - private @Nullable ChangeSetExtent changeSetExtent; private final MaskingExtent maskingExtent; private final BlockChangeLimiter changeLimiter; @@ -224,27 +219,25 @@ public class EditSession implements Extent, AutoCloseable { // These extents are ALWAYS used extent = fastModeExtent = new FastModeExtent(world, false); extent = survivalExtent = new SurvivalModeExtent(extent, world); - extent = quirkExtent = new BlockQuirkExtent(extent, world); - extent = chunkLoadingExtent = new ChunkLoadingExtent(extent, world); - extent = cacheExtent = new LastAccessExtentCache(extent); - extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE); - extent = validator = new DataValidatorExtent(extent, world); + extent = new BlockQuirkExtent(extent, world); + extent = new ChunkLoadingExtent(extent, world); + extent = new LastAccessExtentCache(extent); extent = blockBagExtent = new BlockBagExtent(extent, blockBag); + extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE); + this.bypassReorderHistory = new DataValidatorExtent(extent, world); // This extent can be skipped by calling rawSetBlock() extent = reorderExtent = new MultiStageReorder(extent, false); extent = chunkBatchingExtent = new ChunkBatchingExtent(extent); extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER); + this.bypassHistory = new DataValidatorExtent(extent, world); // These extents can be skipped by calling smartSetBlock() - extent = changeSetExtent = new ChangeSetExtent(extent, changeSet); + extent = new ChangeSetExtent(extent, changeSet); extent = maskingExtent = new MaskingExtent(extent, Masks.alwaysTrue()); extent = changeLimiter = new BlockChangeLimiter(extent, maxBlocks); extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY); - - this.bypassReorderHistory = blockBagExtent; - this.bypassHistory = reorderExtent; - this.bypassNone = extent; + this.bypassNone = new DataValidatorExtent(extent, world); } else { Extent extent = new NullExtent(); extent = survivalExtent = new SurvivalModeExtent(extent, NullWorld.getInstance()); From a0b9810c446018552ad1405e063a0f82956afeb5 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Tue, 13 Aug 2019 20:06:15 -0700 Subject: [PATCH 323/366] [Doctools] Read source files for command ordering --- worldedit-core/doctools/build.gradle.kts | 1 + .../internal/util/DocumentationPrinter.kt | 23 +++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/worldedit-core/doctools/build.gradle.kts b/worldedit-core/doctools/build.gradle.kts index 803e1078e..66aa2285f 100644 --- a/worldedit-core/doctools/build.gradle.kts +++ b/worldedit-core/doctools/build.gradle.kts @@ -14,4 +14,5 @@ dependencies { "implementation"(project(":worldedit-libs:core:ap")) "implementation"(project(":worldedit-core")) "implementation"(kotlin("stdlib-jdk8")) + "implementation"(kotlin("reflect")) } diff --git a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt index 768830857..dd06e46a3 100644 --- a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt @@ -48,10 +48,10 @@ import java.nio.file.Files import java.nio.file.Paths import java.util.stream.Stream import kotlin.streams.toList -import org.enginehub.piston.annotation.Command as CommandAnnotation class DocumentationPrinter private constructor() { + private val nameRegex = Regex("name = \"(.+?)\"") private val serializer = PlainComponentSerializer({ "" }, TranslatableComponent::key) private val commands = WorldEdit.getInstance().platformManager.platformCommandManager.commandManager.allCommands .map { it.name to it }.toList().toMap() @@ -59,10 +59,19 @@ class DocumentationPrinter private constructor() { private val permsOutput = StringBuilder() private suspend inline fun SequenceScope.yieldAllCommandsIn() { - for (method in T::class.java.methods) { - val cmdAnno = method.getDeclaredAnnotation(CommandAnnotation::class.java) - if (cmdAnno != null) { - yield(cmdAnno.name) + val sourceFile = Paths.get("worldedit-core/src/main/java/" + T::class.qualifiedName!!.replace('.', '/') + ".java") + require(Files.exists(sourceFile)) { "Source not found for ${T::class.qualifiedName}"} + Files.newBufferedReader(sourceFile).useLines { lines -> + var inCommand = false + for (line in lines) { + if (inCommand) { + when (val match = nameRegex.find(line)) { + null -> if (line.trim() == ")") inCommand = false + else -> yield(match.groupValues[1]) + } + } else if (line.contains("@Command(")) { + inCommand = true + } } } } @@ -219,8 +228,7 @@ Other Permissions private fun cmdsToPerms(cmds: List, prefix: String) { cmds.forEach { c -> permsOutput.append(" ").append(cmdToPerm(prefix, c)).append("\n") - c.parts.filter { p -> p is SubCommandPart } - .map { p -> p as SubCommandPart } + c.parts.filterIsInstance() .forEach { scp -> cmdsToPerms(scp.commands.sortedBy { it.name }, prefix + c.name + " ") } @@ -260,6 +268,7 @@ Other Permissions cmdOutput.appendln() for ((k, v) in entries) { val rstSafe = v.replace("\"", "\\\"").replace("\n", "\n" + " ".repeat(2)) + .lineSequence().map { line -> line.ifBlank { "" } }.joinToString(separator = "\n") cmdOutput.append(" ".repeat(2)) .append(k) .append(",") From 0620478763bfd5355a6350ed06f9c6ee1741de8b Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sun, 25 Aug 2019 19:58:28 +1000 Subject: [PATCH 324/366] feature(cli): Added a CLI version of WorldEdit, and allowed most commands to be run from console (#508) * Re-do commits to avoid awful rebase * You can load and save a schematic file now. Still gotta setup ability to use commands as a console actor. * Add a world override concept to LocalSession, and allow a lot more commands to be performed by actors. * Fixed commands, and set the loaded schematic as the world override in CLI * Properly load tags * Added 1.14.4 data values * Allow a majority of commands to be performed by the console. * Fixed a lot of PR requested changes * Added a Locatable interface and use that for getting the location of the player in commands. * Added script support. Currently requires a newline at the end of the script. * Shade everything to allow this to run locally - should probably minimize this to an extent later. * Actually hook up the version * Added a //world command to set the override * Fixed a missed checkstyle issue * Added CommandBlock support to Bukkit * Make command block support configurable * Minor cleanup and implementing a few of the final functions * Fixed most issues from PR * Improve UX, saving is now automatic and unknown command messages show * Better save docs and support any clipboard format * Include the entire formats list * Arrays.copyOf * Clear the world override if the selector is called on another world. * Update logging extent to allow basic logging with non-player actors --- config/checkstyle/import-control.xml | 5 + settings.gradle.kts | 2 +- .../bukkit/BukkitBlockCategoryRegistry.java | 6 - .../bukkit/BukkitBlockCommandSender.java | 160 +++++++++ .../worldedit/bukkit/BukkitCommandSender.java | 36 +- .../worldedit/bukkit/BukkitConfiguration.java | 2 + .../bukkit/BukkitItemCategoryRegistry.java | 6 - .../sk89q/worldedit/bukkit/BukkitWorld.java | 6 + .../worldedit/bukkit/WorldEditPlugin.java | 3 + .../src/main/resources/defaults/config.yml | 1 + worldedit-cli/build.gradle.kts | 33 ++ .../cli/CLIBlockCategoryRegistry.java | 37 ++ .../sk89q/worldedit/cli/CLIBlockRegistry.java | 73 ++++ .../sk89q/worldedit/cli/CLICommandSender.java | 164 +++++++++ .../sk89q/worldedit/cli/CLIConfiguration.java | 40 +++ .../cli/CLIItemCategoryRegistry.java | 36 ++ .../com/sk89q/worldedit/cli/CLIPlatform.java | 159 +++++++++ .../sk89q/worldedit/cli/CLIRegistries.java | 64 ++++ .../com/sk89q/worldedit/cli/CLIWorld.java | 44 +++ .../com/sk89q/worldedit/cli/CLIWorldEdit.java | 335 ++++++++++++++++++ .../worldedit/cli/data/FileRegistries.java | 77 ++++ .../cli/schematic/ClipboardWorld.java | 217 ++++++++++++ .../com/sk89q/worldedit/cli/data/1631.json | 1 + .../com/sk89q/worldedit/cli/data/1963.json | 1 + .../com/sk89q/worldedit/cli/data/1968.json | 1 + .../com/sk89q/worldedit/cli/data/1976.json | 1 + .../resources/defaults/worldedit.properties | 33 ++ worldedit-cli/src/main/resources/log4j2.xml | 21 ++ .../sk89q/worldedit/EditSessionFactory.java | 20 +- .../com/sk89q/worldedit/LocalSession.java | 86 +++-- .../worldedit/MissingWorldException.java | 27 ++ .../java/com/sk89q/worldedit/WorldEdit.java | 22 +- .../worldedit/command/ChunkCommands.java | 24 +- .../worldedit/command/ClipboardCommands.java | 43 +-- .../worldedit/command/ExpandCommands.java | 12 +- .../worldedit/command/GeneralCommands.java | 52 ++- .../worldedit/command/GenerationCommands.java | 76 ++-- .../worldedit/command/HistoryCommands.java | 5 +- .../worldedit/command/RegionCommands.java | 99 +++--- .../worldedit/command/SchematicCommands.java | 42 +-- .../worldedit/command/SelectionCommands.java | 126 +++---- .../worldedit/command/SnapshotCommands.java | 70 ++-- .../command/SnapshotUtilCommands.java | 31 +- .../worldedit/command/UtilityCommands.java | 130 +++---- .../worldedit/command/WorldEditCommands.java | 17 +- .../command/argument/WorldConverter.java | 81 +++++ .../worldedit/command/tool/SelectionWand.java | 3 +- .../com/sk89q/worldedit/entity/Entity.java | 26 +- .../com/sk89q/worldedit/entity/Player.java | 13 +- .../platform/AbstractNonPlayerActor.java | 51 +++ .../platform/AbstractPlayerActor.java | 17 +- .../extension/platform/Locatable.java | 69 ++++ .../platform/PlatformCommandManager.java | 73 ++-- .../worldedit/extent/clipboard/Clipboard.java | 2 +- .../extent/clipboard/io/ClipboardReader.java | 9 + .../clipboard/io/SpongeSchematicReader.java | 45 ++- .../command/CommandLoggingHandler.java | 24 +- .../WorldEditExceptionConverter.java | 6 + .../sk89q/worldedit/world/AbstractWorld.java | 20 ++ .../com/sk89q/worldedit/world/NullWorld.java | 5 + .../java/com/sk89q/worldedit/world/World.java | 3 +- .../world/registry/CategoryRegistry.java | 4 +- .../registry/NullBlockCategoryRegistry.java | 6 - .../registry/NullItemCategoryRegistry.java | 6 - .../fabric/FabricBlockCategoryRegistry.java | 6 - .../fabric/FabricItemCategoryRegistry.java | 6 - .../sk89q/worldedit/fabric/FabricWorld.java | 8 + .../forge/ForgeBlockCategoryRegistry.java | 6 - .../forge/ForgeItemCategoryRegistry.java | 6 - .../com/sk89q/worldedit/forge/ForgeWorld.java | 6 + worldedit-libs/cli/build.gradle.kts | 1 + .../sk89q/worldedit/sponge/SpongeWorld.java | 7 + 72 files changed, 2386 insertions(+), 569 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java create mode 100644 worldedit-cli/build.gradle.kts create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIBlockCategoryRegistry.java create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIBlockRegistry.java create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLICommandSender.java create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIConfiguration.java create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIItemCategoryRegistry.java create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIRegistries.java create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorld.java create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/data/FileRegistries.java create mode 100644 worldedit-cli/src/main/java/com/sk89q/worldedit/cli/schematic/ClipboardWorld.java create mode 100644 worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1631.json create mode 100644 worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1963.json create mode 100644 worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1968.json create mode 100644 worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1976.json create mode 100644 worldedit-cli/src/main/resources/defaults/worldedit.properties create mode 100644 worldedit-cli/src/main/resources/log4j2.xml create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/MissingWorldException.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Locatable.java create mode 100644 worldedit-libs/cli/build.gradle.kts diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index e26e9a388..07b74fba9 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -48,6 +48,11 @@ + + + + + diff --git a/settings.gradle.kts b/settings.gradle.kts index 6da7bedcc..2a4044c95 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,7 +2,7 @@ rootProject.name = "worldedit" include("worldedit-libs") -listOf("bukkit", "core", "forge", "sponge", "fabric").forEach { +listOf("bukkit", "core", "forge", "sponge", "fabric", "cli").forEach { include("worldedit-libs:$it") include("worldedit-$it") } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCategoryRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCategoryRegistry.java index cecec0691..c6d6fd9b0 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCategoryRegistry.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCategoryRegistry.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.bukkit; -import com.sk89q.worldedit.registry.Category; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; import org.bukkit.Bukkit; @@ -44,9 +43,4 @@ public class BukkitBlockCategoryRegistry implements BlockCategoryRegistry { Tag tag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, new NamespacedKey(namespace, key), Material.class); return getFromBukkitTag(tag); } - - @Override - public Set getAll(Category category) { - return getCategorisedByName(category.getId()); - } } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java new file mode 100644 index 000000000..d87462322 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java @@ -0,0 +1,160 @@ +/* + * 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.bukkit; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.sk89q.worldedit.extension.platform.AbstractNonPlayerActor; +import com.sk89q.worldedit.extension.platform.Locatable; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.session.SessionKey; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import org.bukkit.Material; +import org.bukkit.command.BlockCommandSender; + +import java.util.UUID; + +import javax.annotation.Nullable; + +public class BukkitBlockCommandSender extends AbstractNonPlayerActor implements Locatable { + + private final BlockCommandSender sender; + private final WorldEditPlugin plugin; + private final Location location; + private final UUID uuid; + + public BukkitBlockCommandSender(WorldEditPlugin plugin, BlockCommandSender sender) { + checkNotNull(plugin); + checkNotNull(sender); + + this.plugin = plugin; + this.sender = sender; + this.location = BukkitAdapter.adapt(sender.getBlock().getLocation()); + this.uuid = new UUID(location.toVector().toBlockPoint().hashCode(), location.getExtent().hashCode()); + } + + @Override + public String getName() { + return sender.getName(); + } + + @Override + public void printRaw(String msg) { + for (String part : msg.split("\n")) { + sender.sendMessage(part); + } + } + + @Override + public void print(String msg) { + for (String part : msg.split("\n")) { + print(TextComponent.of(part, TextColor.LIGHT_PURPLE)); + } + } + + @Override + public void printDebug(String msg) { + for (String part : msg.split("\n")) { + print(TextComponent.of(part, TextColor.GRAY)); + } + } + + @Override + public void printError(String msg) { + for (String part : msg.split("\n")) { + print(TextComponent.of(part, TextColor.RED)); + } + } + + @Override + public void print(Component component) { + TextAdapter.sendComponent(sender, component); + } + + @Override + public Location getLocation() { + return this.location; + } + + @Override + public boolean setLocation(Location location) { + return false; + } + + @Override + public Extent getExtent() { + return this.location.getExtent(); + } + + @Override + public UUID getUniqueId() { + return uuid; + } + + @Override + public String[] getGroups() { + return new String[0]; + } + + @Override + public void checkPermission(String permission) throws AuthorizationException { + if (!hasPermission(permission)) { + throw new AuthorizationException(); + } + } + + @Override + public boolean hasPermission(String permission) { + return sender.hasPermission(permission); + } + + @Override + public SessionKey getSessionKey() { + return new SessionKey() { + @Nullable + @Override + public String getName() { + return sender.getName(); + } + + @Override + public boolean isActive() { + return sender.getBlock().getType() == Material.COMMAND_BLOCK + || sender.getBlock().getType() == Material.CHAIN_COMMAND_BLOCK + || sender.getBlock().getType() == Material.REPEATING_COMMAND_BLOCK; + } + + @Override + public boolean isPersistent() { + return false; + } + + @Override + public UUID getUniqueId() { + return uuid; + } + }; + } +} diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java index 2d4ea70cf..f1ac08599 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java @@ -22,8 +22,7 @@ package com.sk89q.worldedit.bukkit; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.extension.platform.AbstractNonPlayerActor; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.auth.AuthorizationException; import com.sk89q.worldedit.util.formatting.text.Component; @@ -31,12 +30,11 @@ import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.io.File; import java.util.UUID; import javax.annotation.Nullable; -public class BukkitCommandSender implements Actor { +public class BukkitCommandSender extends AbstractNonPlayerActor { /** * One time generated ID. @@ -98,11 +96,6 @@ public class BukkitCommandSender implements Actor { TextAdapter.sendComponent(sender, component); } - @Override - public boolean canDestroyBedrock() { - return true; - } - @Override public String[] getGroups() { return new String[0]; @@ -117,42 +110,23 @@ public class BukkitCommandSender implements Actor { public void checkPermission(String permission) throws AuthorizationException { } - @Override - public boolean isPlayer() { - return false; - } - - @Override - public File openFileOpenDialog(String[] extensions) { - return null; - } - - @Override - public File openFileSaveDialog(String[] extensions) { - return null; - } - - @Override - public void dispatchCUIEvent(CUIEvent event) { - } - @Override public SessionKey getSessionKey() { return new SessionKey() { @Nullable @Override public String getName() { - return null; + return sender.getName(); } @Override public boolean isActive() { - return false; + return true; } @Override public boolean isPersistent() { - return false; + return true; } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java index 96c755083..ee975b837 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitConfiguration.java @@ -32,6 +32,7 @@ import java.io.File; public class BukkitConfiguration extends YAMLConfiguration { public boolean noOpPermissions = false; + public boolean commandBlockSupport = false; @Unreported private final WorldEditPlugin plugin; public BukkitConfiguration(YAMLProcessor config, WorldEditPlugin plugin) { @@ -43,6 +44,7 @@ public class BukkitConfiguration extends YAMLConfiguration { public void load() { super.load(); noOpPermissions = config.getBoolean("no-op-permissions", false); + commandBlockSupport = config.getBoolean("command-block-support", false); migrateLegacyFolders(); } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitItemCategoryRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitItemCategoryRegistry.java index c75c56eb2..2beb469e5 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitItemCategoryRegistry.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitItemCategoryRegistry.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.bukkit; -import com.sk89q.worldedit.registry.Category; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; import org.bukkit.Bukkit; @@ -44,9 +43,4 @@ public class BukkitItemCategoryRegistry implements ItemCategoryRegistry { Tag tag = Bukkit.getTag(Tag.REGISTRY_ITEMS, new NamespacedKey(namespace, key), Material.class); return getFromBukkitTag(tag); } - - @Override - public Set getAll(Category category) { - return getCategorisedByName(category.getId()); - } } 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 438c43cbd..861265952 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 @@ -58,6 +58,7 @@ import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import static com.google.common.base.Preconditions.checkNotNull; @@ -159,6 +160,11 @@ public class BukkitWorld extends AbstractWorld { return getWorld().getName(); } + @Override + public String getId() { + return getWorld().getName().replace(" ", "_").toLowerCase(Locale.ROOT); + } + @Override public Path getStoragePath() { return getWorld().getWorldFolder().toPath(); 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 69e53ee5b..8cbd499dd 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 @@ -56,6 +56,7 @@ import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Tag; import org.bukkit.block.Biome; +import org.bukkit.command.BlockCommandSender; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; @@ -432,6 +433,8 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { public Actor wrapCommandSender(CommandSender sender) { if (sender instanceof Player) { return wrapPlayer((Player) sender); + } else if (config.commandBlockSupport && sender instanceof BlockCommandSender) { + return new BukkitBlockCommandSender(this, (BlockCommandSender) sender); } return new BukkitCommandSender(this, sender); diff --git a/worldedit-bukkit/src/main/resources/defaults/config.yml b/worldedit-bukkit/src/main/resources/defaults/config.yml index a67dfb37c..32ecab7cf 100644 --- a/worldedit-bukkit/src/main/resources/defaults/config.yml +++ b/worldedit-bukkit/src/main/resources/defaults/config.yml @@ -149,3 +149,4 @@ no-op-permissions: false debug: false show-help-on-first-use: true server-side-cui: true +command-block-support: false diff --git a/worldedit-cli/build.gradle.kts b/worldedit-cli/build.gradle.kts new file mode 100644 index 000000000..ea047b641 --- /dev/null +++ b/worldedit-cli/build.gradle.kts @@ -0,0 +1,33 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +applyPlatformAndCoreConfiguration() +applyShadowConfiguration() + +dependencies { + "compile"(project(":worldedit-core")) + "compile"("org.apache.logging.log4j:log4j-core:2.8.1") + "compile"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1") + "compile"("commons-cli:commons-cli:1.4") +} + +tasks.named("jar") { + manifest { + attributes( + "Implementation-Version" to project.version, + "Main-Class" to "com.sk89q.worldedit.cli.CLIWorldEdit" + ) + } +} + +tasks.named("shadowJar") { + dependencies { + include { true } + } + minimize { + exclude { true } + } +} + +tasks.named("assemble").configure { + dependsOn("shadowJar") +} diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIBlockCategoryRegistry.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIBlockCategoryRegistry.java new file mode 100644 index 000000000..697e9e521 --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIBlockCategoryRegistry.java @@ -0,0 +1,37 @@ +/* + * 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.cli; + +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; + +import java.util.Collections; +import java.util.Set; +import java.util.stream.Collectors; + +public class CLIBlockCategoryRegistry implements BlockCategoryRegistry { + + @Override + public Set getCategorisedByName(String category) { + return CLIWorldEdit.inst.getFileRegistries().getDataFile().blocktags.getOrDefault(category, Collections.emptyList()).stream() + .map(BlockType.REGISTRY::get) + .collect(Collectors.toSet()); + } +} diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIBlockRegistry.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIBlockRegistry.java new file mode 100644 index 000000000..7cc74f45a --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIBlockRegistry.java @@ -0,0 +1,73 @@ +/* + * 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.cli; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.sk89q.worldedit.cli.data.FileRegistries; +import com.sk89q.worldedit.registry.state.BooleanProperty; +import com.sk89q.worldedit.registry.state.DirectionalProperty; +import com.sk89q.worldedit.registry.state.EnumProperty; +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.BlockType; +import com.sk89q.worldedit.world.registry.BundledBlockRegistry; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; + +public class CLIBlockRegistry extends BundledBlockRegistry { + + private Property createProperty(String type, String key, List values) { + switch (type) { + case "int": { + List fixedValues = values.stream().map(Integer::parseInt).collect(Collectors.toList()); + return new IntegerProperty(key, fixedValues); + } + case "bool": { + List fixedValues = values.stream().map(Boolean::parseBoolean).collect(Collectors.toList()); + return new BooleanProperty(key, fixedValues); + } + case "enum": { + return new EnumProperty(key, values); + } + case "direction": { + List fixedValues = values.stream().map(String::toUpperCase).map(Direction::valueOf).collect(Collectors.toList()); + return new DirectionalProperty(key, fixedValues); + } + default: + throw new RuntimeException("Failed to create property"); + } + } + + @Nullable + @Override + public Map> getProperties(BlockType blockType) { + Map properties = + CLIWorldEdit.inst.getFileRegistries().getDataFile().blocks.get(blockType.getId()).properties; + return ImmutableMap.copyOf(Maps.transformEntries(properties, + (Maps.EntryTransformer>) + (key, value) -> createProperty(value.type, key, value.values))); + } +} diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLICommandSender.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLICommandSender.java new file mode 100644 index 000000000..0c9cb22f8 --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLICommandSender.java @@ -0,0 +1,164 @@ +/* + * 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.cli; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.internal.cui.CUIEvent; +import com.sk89q.worldedit.session.SessionKey; +import com.sk89q.worldedit.util.FileDialogUtil; +import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer; +import org.slf4j.Logger; + +import java.io.File; +import java.util.UUID; + +public class CLICommandSender implements Actor { + + /** + * One time generated ID. + */ + private static final UUID DEFAULT_ID = UUID.fromString("a233eb4b-4cab-42cd-9fd9-7e7b9a3f74be"); + + private final CLIWorldEdit app; + private final Logger sender; + + public CLICommandSender(CLIWorldEdit app, Logger sender) { + checkNotNull(app); + checkNotNull(sender); + + this.app = app; + this.sender = sender; + } + + @Override + public UUID getUniqueId() { + return DEFAULT_ID; + } + + @Override + public String getName() { + return "Console"; + } + + @Override + public void printRaw(String msg) { + for (String part : msg.split("\n")) { + sender.info(part); + } + } + + private static final String ANSI_PURPLE = "\u001B[35m"; + private static final String ANSI_RED = "\u001B[31m"; + private static final String ANSI_GREEN = "\u001B[32m"; + private static final String ANSI_RESET = "\u001B[0m"; + + @Override + public void print(String msg) { + for (String part : msg.split("\n")) { + sender.info(ANSI_PURPLE + part + ANSI_RESET); + } + } + + @Override + public void printDebug(String msg) { + for (String part : msg.split("\n")) { + sender.debug(ANSI_GREEN + part + ANSI_RESET); + } + } + + @Override + public void printError(String msg) { + for (String part : msg.split("\n")) { + sender.error(ANSI_RED + part + ANSI_RESET); + } + } + + @Override + public void print(Component component) { + print(PlainComponentSerializer.INSTANCE.serialize(component)); + } + + @Override + public boolean canDestroyBedrock() { + return true; + } + + @Override + public String[] getGroups() { + return new String[0]; + } + + @Override + public boolean hasPermission(String perm) { + return true; + } + + @Override + public void checkPermission(String permission) throws AuthorizationException { + } + + @Override + public boolean isPlayer() { + return false; + } + + @Override + public File openFileOpenDialog(String[] extensions) { + return FileDialogUtil.showOpenDialog(extensions); + } + + @Override + public File openFileSaveDialog(String[] extensions) { + return FileDialogUtil.showSaveDialog(extensions); + } + + @Override + public void dispatchCUIEvent(CUIEvent event) { + } + + @Override + public SessionKey getSessionKey() { + return new SessionKey() { + @Override + public String getName() { + return "Console"; + } + + @Override + public boolean isActive() { + return true; + } + + @Override + public boolean isPersistent() { + return true; + } + + @Override + public UUID getUniqueId() { + return DEFAULT_ID; + } + }; + } +} diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIConfiguration.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIConfiguration.java new file mode 100644 index 000000000..95adb23aa --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIConfiguration.java @@ -0,0 +1,40 @@ +/* + * 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.cli; + +import com.sk89q.worldedit.util.PropertiesConfiguration; + +import java.io.File; + +public class CLIConfiguration extends PropertiesConfiguration { + + public CLIConfiguration(CLIWorldEdit app) { + super(app.getWorkingDir().resolve("worldedit.properties").toFile()); + } + + @Override + protected void loadExtra() { + } + + @Override + public File getWorkingDirectory() { + return CLIWorldEdit.inst.getWorkingDir().toFile(); + } +} \ No newline at end of file diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIItemCategoryRegistry.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIItemCategoryRegistry.java new file mode 100644 index 000000000..40b99b59a --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIItemCategoryRegistry.java @@ -0,0 +1,36 @@ +/* + * 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.cli; + +import com.sk89q.worldedit.world.item.ItemType; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; + +import java.util.Set; +import java.util.stream.Collectors; + +public class CLIItemCategoryRegistry implements ItemCategoryRegistry { + + @Override + public Set getCategorisedByName(String category) { + return CLIWorldEdit.inst.getFileRegistries().getDataFile().itemtags.get(category).stream() + .map(ItemType.REGISTRY::get) + .collect(Collectors.toSet()); + } +} diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java new file mode 100644 index 000000000..c2e9eaba9 --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIPlatform.java @@ -0,0 +1,159 @@ +/* + * 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.cli; + +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.AbstractPlatform; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.world.DataFixer; +import com.sk89q.worldedit.world.World; +import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.registry.Registries; +import org.enginehub.piston.CommandManager; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +import javax.annotation.Nullable; + +class CLIPlatform extends AbstractPlatform { + + private final CLIWorldEdit app; + private int dataVersion = -1; + + private final List worlds = new ArrayList<>(); + private final Timer timer = new Timer(); + private int lastTimerId = 0; + + CLIPlatform(CLIWorldEdit app) { + this.app = app; + } + + @Override + public Registries getRegistries() { + return CLIRegistries.getInstance(); + } + + @Override + public int getDataVersion() { + return this.dataVersion; + } + + public void setDataVersion(int dataVersion) { + this.dataVersion = dataVersion; + } + + @Override + public DataFixer getDataFixer() { + return null; + } + + @Override + public boolean isValidMobType(String type) { + return EntityTypes.get(type) != null; + } + + @Override + public void reload() { + getConfiguration().load(); + } + + @Override + public int schedule(long delay, long period, Runnable task) { + this.timer.schedule(new TimerTask() { + @Override + public void run() { + task.run(); + if (period >= 0) { + timer.schedule(this, period); + } + } + }, delay); + return this.lastTimerId++; + } + + @Override + public List getWorlds() { + return this.worlds; + } + + @Nullable + @Override + public Player matchPlayer(Player player) { + return null; + } + + @Nullable + @Override + public World matchWorld(World world) { + return this.worlds.stream() + .filter(w -> w.getId().equals(world.getId())) + .findAny() + .orElse(null); + } + + @Override + public void registerCommands(CommandManager manager) { + } + + @Override + public void registerGameHooks() { + } + + @Override + public CLIConfiguration getConfiguration() { + return app.getConfig(); + } + + @Override + public String getVersion() { + return app.getInternalVersion(); + } + + @Override + public String getPlatformName() { + return "CLI-Official"; + } + + @Override + public String getPlatformVersion() { + return app.getInternalVersion(); + } + + @Override + public Map getCapabilities() { + Map capabilities = new EnumMap<>(Capability.class); + capabilities.put(Capability.CONFIGURATION, Preference.PREFER_OTHERS); + capabilities.put(Capability.GAME_HOOKS, Preference.NORMAL); + capabilities.put(Capability.PERMISSIONS, Preference.NORMAL); + capabilities.put(Capability.USER_COMMANDS, Preference.NORMAL); + capabilities.put(Capability.WORLD_EDITING, Preference.PREFERRED); + return capabilities; + } + + public void addWorld(World world) { + worlds.add(world); + } +} diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIRegistries.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIRegistries.java new file mode 100644 index 000000000..82e7119d6 --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIRegistries.java @@ -0,0 +1,64 @@ +/* + * 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.cli; + +import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; +import com.sk89q.worldedit.world.registry.BlockRegistry; +import com.sk89q.worldedit.world.registry.BundledRegistries; +import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; + +public class CLIRegistries extends BundledRegistries { + + private static final CLIRegistries INSTANCE = new CLIRegistries(); + private final BlockRegistry blockRegistry = new CLIBlockRegistry(); + private final BlockCategoryRegistry blockCategoryRegistry = new CLIBlockCategoryRegistry(); + private final ItemCategoryRegistry itemCategoryRegistry = new CLIItemCategoryRegistry(); + + /** + * Create a new instance. + */ + private CLIRegistries() { + } + + @Override + public BlockRegistry getBlockRegistry() { + return blockRegistry; + } + + @Override + public BlockCategoryRegistry getBlockCategoryRegistry() { + return blockCategoryRegistry; + } + + @Override + public ItemCategoryRegistry getItemCategoryRegistry() { + return itemCategoryRegistry; + } + + /** + * Get a static instance. + * + * @return an instance + */ + public static CLIRegistries getInstance() { + return INSTANCE; + } + +} diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorld.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorld.java new file mode 100644 index 000000000..7df65f333 --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorld.java @@ -0,0 +1,44 @@ +/* + * 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.cli; + +public interface CLIWorld { + + /** + * Saves this world back to file if dirty or forced. + * + * @param force Force a save + */ + void save(boolean force); + + /** + * Gets whether the world is dirty. + * + * @return If it's dirty + */ + boolean isDirty(); + + /** + * Set the world's dirty status + * + * @param dirty if dirty + */ + void setDirty(boolean dirty); +} diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java new file mode 100644 index 000000000..ba77fb1f2 --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLIWorldEdit.java @@ -0,0 +1,335 @@ +/* + * 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.cli; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.cli.data.FileRegistries; +import com.sk89q.worldedit.cli.schematic.ClipboardWorld; +import com.sk89q.worldedit.event.platform.CommandEvent; +import com.sk89q.worldedit.event.platform.PlatformReadyEvent; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.block.FuzzyBlockState; +import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.item.ItemCategory; +import com.sk89q.worldedit.world.item.ItemType; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.Options; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.SequenceInputStream; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.Map; +import java.util.Scanner; + +/** + * The CLI implementation of WorldEdit. + */ +public class CLIWorldEdit { + + private static final Logger LOGGER = LoggerFactory.getLogger(CLIWorldEdit.class); + + public static CLIWorldEdit inst; + + private CLIPlatform platform; + private CLIConfiguration config; + private Path workingDir; + private String version; + + private Actor commandSender; + + private FileRegistries fileRegistries; + + public CLIWorldEdit() { + inst = this; + } + + private void setupPlatform() { + this.fileRegistries = new FileRegistries(this); + this.fileRegistries.loadDataFiles(); + + WorldEdit.getInstance().getPlatformManager().register(platform); + } + + public void setupRegistries() { + // Blocks + for (Map.Entry manifestEntry : fileRegistries.getDataFile().blocks.entrySet()) { + if (BlockType.REGISTRY.get(manifestEntry.getKey()) == null) { + BlockType.REGISTRY.register(manifestEntry.getKey(), new BlockType(manifestEntry.getKey(), input -> { + ParserContext context = new ParserContext(); + context.setPreferringWildcard(true); + context.setTryLegacy(false); + context.setRestricted(false); + try { + FuzzyBlockState state = (FuzzyBlockState) WorldEdit.getInstance().getBlockFactory().parseFromInput( + manifestEntry.getValue().defaultstate, + context + ).toImmutableState(); + BlockState defaultState = input.getBlockType().getAllStates().get(0); + for (Map.Entry, Object> propertyObjectEntry : state.getStates().entrySet()) { + @SuppressWarnings("unchecked") + Property prop = (Property) propertyObjectEntry.getKey(); + defaultState = defaultState.with(prop, propertyObjectEntry.getValue()); + } + return defaultState; + } catch (InputParseException e) { + LOGGER.warn("Error loading block state for " + manifestEntry.getKey(), e); + return input; + } + })); + } + } + // Items + for (String name : fileRegistries.getDataFile().items) { + if (ItemType.REGISTRY.get(name) == null) { + ItemType.REGISTRY.register(name, new ItemType(name)); + } + } + // Entities + for (String name : fileRegistries.getDataFile().entities) { + if (EntityType.REGISTRY.get(name) == null) { + EntityType.REGISTRY.register(name, new EntityType(name)); + } + } + // Biomes + for (String name : fileRegistries.getDataFile().biomes) { + if (BiomeType.REGISTRY.get(name) == null) { + BiomeType.REGISTRY.register(name, new BiomeType(name)); + } + } + // Tags + for (String name : fileRegistries.getDataFile().blocktags.keySet()) { + if (BlockCategory.REGISTRY.get(name) == null) { + BlockCategory.REGISTRY.register(name, new BlockCategory(name)); + } + } + for (String name : fileRegistries.getDataFile().itemtags.keySet()) { + if (ItemCategory.REGISTRY.get(name) == null) { + ItemCategory.REGISTRY.register(name, new ItemCategory(name)); + } + } + } + + public void onInitialized() { + // Setup working directory + workingDir = Paths.get("worldedit"); + if (!Files.exists(workingDir)) { + try { + Files.createDirectory(workingDir); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + this.commandSender = new CLICommandSender(this, LOGGER); + this.platform = new CLIPlatform(this); + LOGGER.info("WorldEdit CLI (version " + getInternalVersion() + ") is loaded"); + } + + public void onStarted() { + setupPlatform(); + + setupRegistries(); + WorldEdit.getInstance().loadMappings(); + + config = new CLIConfiguration(this); + config.load(); + + WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent()); + } + + public void onStopped() { + WorldEdit worldEdit = WorldEdit.getInstance(); + worldEdit.getSessionManager().unload(); + worldEdit.getPlatformManager().unregister(platform); + } + + public FileRegistries getFileRegistries() { + return this.fileRegistries; + } + + /** + * Get the configuration. + * + * @return the CLI configuration + */ + CLIConfiguration getConfig() { + return this.config; + } + + /** + * Get the WorldEdit proxy for the platform. + * + * @return the WorldEdit platform + */ + public Platform getPlatform() { + return this.platform; + } + + /** + * Get the working directory where WorldEdit's files are stored. + * + * @return the working directory + */ + public Path getWorkingDir() { + return this.workingDir; + } + + /** + * Get the version of the WorldEdit-CLI implementation. + * + * @return a version string + */ + String getInternalVersion() { + if (version == null) { + version = getClass().getPackage().getImplementationVersion(); + } + return version; + } + + public void saveAllWorlds(boolean force) { + platform.getWorlds().stream() + .filter(world -> world instanceof CLIWorld) + .forEach(world -> ((CLIWorld) world).save(force)); + } + + public void run(InputStream inputStream) { + try (Scanner scanner = new Scanner(inputStream)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.equals("stop")) { + commandSender.print("Stopping!"); + break; + } + CommandEvent event = new CommandEvent(commandSender, line); + WorldEdit.getInstance().getEventBus().post(event); + if (!event.isCancelled()) { + commandSender.printError("Unknown command!"); + } else { + saveAllWorlds(false); + } + } + } finally { + saveAllWorlds(false); + } + } + + public static void main(String[] args) { + Options options = new Options(); + options.addOption("f", "file", true, "The file to load in. Either a schematic, or a level.dat in a world folder."); + options.addOption("s", "script", true, "A file containing a list of commands to run. Newline separated."); + int exitCode = 0; + + CLIWorldEdit app = new CLIWorldEdit(); + app.onInitialized(); + + InputStream inputStream = System.in; + + try { + CommandLine cmd = new DefaultParser().parse(options, args); + + String fileArg = cmd.getOptionValue('f'); + File file; + if (fileArg == null) { + String[] formats = Arrays.copyOf(ClipboardFormats.getFileExtensionArray(), ClipboardFormats.getFileExtensionArray().length + 1); + formats[formats.length - 1] = "dat"; + file = app.commandSender.openFileOpenDialog(formats); + } else { + file = new File(fileArg); + } + if (file == null) { + throw new IllegalArgumentException("A file must be provided!"); + } + if (file.getName().endsWith("level.dat")) { + throw new IllegalArgumentException("level.dat file support is unfinished."); + } else { + ClipboardFormat format = ClipboardFormats.findByFile(file); + if (format != null) { + ClipboardReader dataVersionReader = format + .getReader(Files.newInputStream(file.toPath(), StandardOpenOption.READ)); + int dataVersion = dataVersionReader.getDataVersion() + .orElseThrow(() -> new IllegalArgumentException("Failed to obtain data version from schematic.")); + dataVersionReader.close(); + app.platform.setDataVersion(dataVersion); + app.onStarted(); + try (ClipboardReader clipboardReader = format.getReader(Files.newInputStream(file.toPath(), StandardOpenOption.READ))) { + ClipboardWorld world = new ClipboardWorld( + file, + clipboardReader.read(), + file.getName() + ); + app.platform.addWorld(world); + WorldEdit.getInstance().getSessionManager().get(app.commandSender).setWorldOverride(world); + } + } else { + throw new IllegalArgumentException("Unknown file provided!"); + } + } + + String scriptFile = cmd.getOptionValue('s'); + if (scriptFile != null) { + File scriptFileHandle = new File(scriptFile); + if (!scriptFileHandle.exists()) { + throw new IllegalArgumentException("Could not find given script file."); + } + InputStream scriptStream = Files.newInputStream(scriptFileHandle.toPath(), StandardOpenOption.READ); + InputStream newLineStream = new ByteArrayInputStream("\n".getBytes(StandardCharsets.UTF_8)); + // Cleaner to do this than make an Enumeration :( + inputStream = new SequenceInputStream(new SequenceInputStream(scriptStream, newLineStream), inputStream); + } + + app.run(inputStream); + } catch (Exception e) { + e.printStackTrace(); + exitCode = 1; + } finally { + app.onStopped(); + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + System.exit(exitCode); + } +} diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/data/FileRegistries.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/data/FileRegistries.java new file mode 100644 index 000000000..dbaad7edf --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/data/FileRegistries.java @@ -0,0 +1,77 @@ +/* + * 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.cli.data; + +import com.google.common.io.Resources; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.sk89q.worldedit.cli.CLIWorldEdit; +import com.sk89q.worldedit.util.io.ResourceLoader; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; + +public class FileRegistries { + + private CLIWorldEdit app; + private Gson gson = new GsonBuilder().create(); + + private DataFile dataFile; + + public FileRegistries(CLIWorldEdit app) { + this.app = app; + } + + public void loadDataFiles() { + try { + URL url = ResourceLoader.getResource(FileRegistries.class, app.getPlatform().getDataVersion() + ".json"); + this.dataFile = gson.fromJson(Resources.toString(url, StandardCharsets.UTF_8), DataFile.class); + } catch (IOException e) { + throw new RuntimeException("The provided file is not compatible with this version of WorldEdit-CLI. Please update or report this."); + } + } + + public DataFile getDataFile() { + return this.dataFile; + } + + public static class BlockManifest { + public String defaultstate; + public Map properties; + } + + public static class BlockProperty { + public List values; + public String type; + } + + public static class DataFile { + public Map> itemtags; + public Map> blocktags; + public Map> entitytags; + public List items; + public List entities; + public List biomes; + public Map blocks; + } +} diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/schematic/ClipboardWorld.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/schematic/ClipboardWorld.java new file mode 100644 index 000000000..69d1cb1c9 --- /dev/null +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/schematic/ClipboardWorld.java @@ -0,0 +1,217 @@ +/* + * 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.cli.schematic; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.cli.CLIWorld; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.math.BlockVector2; +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.util.TreeGenerator; +import com.sk89q.worldedit.world.AbstractWorld; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Locale; + +import javax.annotation.Nullable; + +public class ClipboardWorld extends AbstractWorld implements Clipboard, CLIWorld { + + private final File file; + private final Clipboard clipboard; + private final String name; + + private boolean dirty = false; + + public ClipboardWorld(File file, Clipboard clipboard, String name) { + this.file = file; + this.clipboard = clipboard; + this.name = name; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getId() { + return getName().replace(" ", "_").toLowerCase(Locale.ROOT); + } + + @Override + public > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) + throws WorldEditException { + dirty = true; + return clipboard.setBlock(position, block); + } + + @Override + public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException { + return false; + } + + @Override + public int getBlockLightLevel(BlockVector3 position) { + return 0; + } + + @Override + public boolean clearContainerBlockContents(BlockVector3 position) { + return false; + } + + @Override + public void dropItem(Vector3 position, BaseItemStack item) { + } + + @Override + public void simulateBlockMine(BlockVector3 position) { + } + + @Override + public boolean regenerate(Region region, EditSession editSession) { + return false; + } + + @Override + public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) + throws MaxChangedBlocksException { + return false; + } + + @Override + public BlockVector3 getSpawnPosition() { + return clipboard.getOrigin(); + } + + @Override + public List getEntities(Region region) { + return clipboard.getEntities(region); + } + + @Override + public List getEntities() { + return clipboard.getEntities(); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + dirty = true; + return clipboard.createEntity(location, entity); + } + + @Override + public BlockState getBlock(BlockVector3 position) { + return clipboard.getBlock(position); + } + + @Override + public BaseBlock getFullBlock(BlockVector3 position) { + return clipboard.getFullBlock(position); + } + + @Override + public BiomeType getBiome(BlockVector2 position) { + return clipboard.getBiome(position); + } + + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + dirty = true; + return clipboard.setBiome(position, biome); + } + + @Override + public Region getRegion() { + return clipboard.getRegion(); + } + + @Override + public BlockVector3 getDimensions() { + return clipboard.getDimensions(); + } + + @Override + public BlockVector3 getOrigin() { + return clipboard.getOrigin(); + } + + @Override + public void setOrigin(BlockVector3 origin) { + clipboard.setOrigin(origin); + dirty = true; + } + + @Override + public boolean hasBiomes() { + return clipboard.hasBiomes(); + } + + @Override + public BlockVector3 getMaximumPoint() { + return clipboard.getMaximumPoint(); + } + + @Override + public BlockVector3 getMinimumPoint() { + return clipboard.getMinimumPoint(); + } + + @Override + public void save(boolean force) { + if (dirty || force) { + try (ClipboardWriter writer = ClipboardFormats.findByFile(file).getWriter(new FileOutputStream(file))) { + writer.write(this); + dirty = false; + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + @Override + public boolean isDirty() { + return this.dirty; + } + + @Override + public void setDirty(boolean dirty) { + this.dirty = dirty; + } +} diff --git a/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1631.json b/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1631.json new file mode 100644 index 000000000..7d0e190e1 --- /dev/null +++ b/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1631.json @@ -0,0 +1 @@ +{"blocks":{"minecraft:acacia_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_button[face=wall,facing=north,powered=false]"},"minecraft:acacia_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:acacia_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:acacia_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:acacia_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_leaves[distance=7,persistent=false]"},"minecraft:acacia_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:acacia_log[axis=y]"},"minecraft:acacia_planks":{"properties":{},"defaultstate":"minecraft:acacia_planks"},"minecraft:acacia_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_pressure_plate[powered=false]"},"minecraft:acacia_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:acacia_sapling[stage=0]"},"minecraft:acacia_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_slab[type=bottom,waterlogged=false]"},"minecraft:acacia_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:acacia_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:acacia_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:acacia_wood[axis=y]"},"minecraft:activator_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:activator_rail[powered=false,shape=north_south]"},"minecraft:air":{"properties":{},"defaultstate":"minecraft:air"},"minecraft:allium":{"properties":{},"defaultstate":"minecraft:allium"},"minecraft:andesite":{"properties":{},"defaultstate":"minecraft:andesite"},"minecraft:anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:anvil[facing=north]"},"minecraft:attached_melon_stem":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:attached_melon_stem[facing=north]"},"minecraft:attached_pumpkin_stem":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:attached_pumpkin_stem[facing=north]"},"minecraft:azure_bluet":{"properties":{},"defaultstate":"minecraft:azure_bluet"},"minecraft:barrier":{"properties":{},"defaultstate":"minecraft:barrier"},"minecraft:beacon":{"properties":{},"defaultstate":"minecraft:beacon"},"minecraft:bedrock":{"properties":{},"defaultstate":"minecraft:bedrock"},"minecraft:beetroots":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:beetroots[age=0]"},"minecraft:birch_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_button[face=wall,facing=north,powered=false]"},"minecraft:birch_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:birch_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:birch_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:birch_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_leaves[distance=7,persistent=false]"},"minecraft:birch_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:birch_log[axis=y]"},"minecraft:birch_planks":{"properties":{},"defaultstate":"minecraft:birch_planks"},"minecraft:birch_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_pressure_plate[powered=false]"},"minecraft:birch_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:birch_sapling[stage=0]"},"minecraft:birch_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_slab[type=bottom,waterlogged=false]"},"minecraft:birch_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:birch_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:birch_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:birch_wood[axis=y]"},"minecraft:black_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:black_banner[rotation=0]"},"minecraft:black_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:black_bed[facing=north,occupied=false,part=foot]"},"minecraft:black_carpet":{"properties":{},"defaultstate":"minecraft:black_carpet"},"minecraft:black_concrete":{"properties":{},"defaultstate":"minecraft:black_concrete"},"minecraft:black_concrete_powder":{"properties":{},"defaultstate":"minecraft:black_concrete_powder"},"minecraft:black_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:black_glazed_terracotta[facing=north]"},"minecraft:black_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:black_shulker_box[facing=up]"},"minecraft:black_stained_glass":{"properties":{},"defaultstate":"minecraft:black_stained_glass"},"minecraft:black_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:black_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:black_terracotta":{"properties":{},"defaultstate":"minecraft:black_terracotta"},"minecraft:black_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:black_wall_banner[facing=north]"},"minecraft:black_wool":{"properties":{},"defaultstate":"minecraft:black_wool"},"minecraft:blue_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:blue_banner[rotation=0]"},"minecraft:blue_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:blue_bed[facing=north,occupied=false,part=foot]"},"minecraft:blue_carpet":{"properties":{},"defaultstate":"minecraft:blue_carpet"},"minecraft:blue_concrete":{"properties":{},"defaultstate":"minecraft:blue_concrete"},"minecraft:blue_concrete_powder":{"properties":{},"defaultstate":"minecraft:blue_concrete_powder"},"minecraft:blue_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:blue_glazed_terracotta[facing=north]"},"minecraft:blue_ice":{"properties":{},"defaultstate":"minecraft:blue_ice"},"minecraft:blue_orchid":{"properties":{},"defaultstate":"minecraft:blue_orchid"},"minecraft:blue_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:blue_shulker_box[facing=up]"},"minecraft:blue_stained_glass":{"properties":{},"defaultstate":"minecraft:blue_stained_glass"},"minecraft:blue_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:blue_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:blue_terracotta":{"properties":{},"defaultstate":"minecraft:blue_terracotta"},"minecraft:blue_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:blue_wall_banner[facing=north]"},"minecraft:blue_wool":{"properties":{},"defaultstate":"minecraft:blue_wool"},"minecraft:bone_block":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:bone_block[axis=y]"},"minecraft:bookshelf":{"properties":{},"defaultstate":"minecraft:bookshelf"},"minecraft:brain_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral[waterlogged=true]"},"minecraft:brain_coral_block":{"properties":{},"defaultstate":"minecraft:brain_coral_block"},"minecraft:brain_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral_fan[waterlogged=true]"},"minecraft:brain_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:brewing_stand":{"properties":{"has_bottle_0":{"values":["true","false"],"type":"bool"},"has_bottle_1":{"values":["true","false"],"type":"bool"},"has_bottle_2":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]"},"minecraft:brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_slab[type=bottom,waterlogged=false]"},"minecraft:brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:bricks":{"properties":{},"defaultstate":"minecraft:bricks"},"minecraft:brown_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:brown_banner[rotation=0]"},"minecraft:brown_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:brown_bed[facing=north,occupied=false,part=foot]"},"minecraft:brown_carpet":{"properties":{},"defaultstate":"minecraft:brown_carpet"},"minecraft:brown_concrete":{"properties":{},"defaultstate":"minecraft:brown_concrete"},"minecraft:brown_concrete_powder":{"properties":{},"defaultstate":"minecraft:brown_concrete_powder"},"minecraft:brown_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:brown_glazed_terracotta[facing=north]"},"minecraft:brown_mushroom":{"properties":{},"defaultstate":"minecraft:brown_mushroom"},"minecraft:brown_mushroom_block":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:brown_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:brown_shulker_box[facing=up]"},"minecraft:brown_stained_glass":{"properties":{},"defaultstate":"minecraft:brown_stained_glass"},"minecraft:brown_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brown_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:brown_terracotta":{"properties":{},"defaultstate":"minecraft:brown_terracotta"},"minecraft:brown_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:brown_wall_banner[facing=north]"},"minecraft:brown_wool":{"properties":{},"defaultstate":"minecraft:brown_wool"},"minecraft:bubble_column":{"properties":{"drag":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_column[drag=true]"},"minecraft:bubble_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral[waterlogged=true]"},"minecraft:bubble_coral_block":{"properties":{},"defaultstate":"minecraft:bubble_coral_block"},"minecraft:bubble_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral_fan[waterlogged=true]"},"minecraft:bubble_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:cactus":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:cactus[age=0]"},"minecraft:cake":{"properties":{"bites":{"values":["0","1","2","3","4","5","6"],"type":"int"}},"defaultstate":"minecraft:cake[bites=0]"},"minecraft:carrots":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:carrots[age=0]"},"minecraft:carved_pumpkin":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:carved_pumpkin[facing=north]"},"minecraft:cauldron":{"properties":{"level":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:cauldron[level=0]"},"minecraft:cave_air":{"properties":{},"defaultstate":"minecraft:cave_air"},"minecraft:chain_command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:chain_command_block[conditional=false,facing=north]"},"minecraft:chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"type":{"values":["single","left","right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:chest[facing=north,type=single,waterlogged=false]"},"minecraft:chipped_anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:chipped_anvil[facing=north]"},"minecraft:chiseled_quartz_block":{"properties":{},"defaultstate":"minecraft:chiseled_quartz_block"},"minecraft:chiseled_red_sandstone":{"properties":{},"defaultstate":"minecraft:chiseled_red_sandstone"},"minecraft:chiseled_sandstone":{"properties":{},"defaultstate":"minecraft:chiseled_sandstone"},"minecraft:chiseled_stone_bricks":{"properties":{},"defaultstate":"minecraft:chiseled_stone_bricks"},"minecraft:chorus_flower":{"properties":{"age":{"values":["0","1","2","3","4","5"],"type":"int"}},"defaultstate":"minecraft:chorus_flower[age=0]"},"minecraft:chorus_plant":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]"},"minecraft:clay":{"properties":{},"defaultstate":"minecraft:clay"},"minecraft:coal_block":{"properties":{},"defaultstate":"minecraft:coal_block"},"minecraft:coal_ore":{"properties":{},"defaultstate":"minecraft:coal_ore"},"minecraft:coarse_dirt":{"properties":{},"defaultstate":"minecraft:coarse_dirt"},"minecraft:cobblestone":{"properties":{},"defaultstate":"minecraft:cobblestone"},"minecraft:cobblestone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_slab[type=bottom,waterlogged=false]"},"minecraft:cobblestone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:cobblestone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:cobweb":{"properties":{},"defaultstate":"minecraft:cobweb"},"minecraft:cocoa":{"properties":{"age":{"values":["0","1","2"],"type":"int"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cocoa[age=0,facing=north]"},"minecraft:command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:command_block[conditional=false,facing=north]"},"minecraft:comparator":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"mode":{"values":["compare","subtract"],"type":"enum"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:comparator[facing=north,mode=compare,powered=false]"},"minecraft:conduit":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:conduit[waterlogged=true]"},"minecraft:cracked_stone_bricks":{"properties":{},"defaultstate":"minecraft:cracked_stone_bricks"},"minecraft:crafting_table":{"properties":{},"defaultstate":"minecraft:crafting_table"},"minecraft:creeper_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:creeper_head[rotation=0]"},"minecraft:creeper_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:creeper_wall_head[facing=north]"},"minecraft:cut_red_sandstone":{"properties":{},"defaultstate":"minecraft:cut_red_sandstone"},"minecraft:cut_sandstone":{"properties":{},"defaultstate":"minecraft:cut_sandstone"},"minecraft:cyan_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:cyan_banner[rotation=0]"},"minecraft:cyan_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:cyan_bed[facing=north,occupied=false,part=foot]"},"minecraft:cyan_carpet":{"properties":{},"defaultstate":"minecraft:cyan_carpet"},"minecraft:cyan_concrete":{"properties":{},"defaultstate":"minecraft:cyan_concrete"},"minecraft:cyan_concrete_powder":{"properties":{},"defaultstate":"minecraft:cyan_concrete_powder"},"minecraft:cyan_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cyan_glazed_terracotta[facing=north]"},"minecraft:cyan_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:cyan_shulker_box[facing=up]"},"minecraft:cyan_stained_glass":{"properties":{},"defaultstate":"minecraft:cyan_stained_glass"},"minecraft:cyan_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cyan_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:cyan_terracotta":{"properties":{},"defaultstate":"minecraft:cyan_terracotta"},"minecraft:cyan_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cyan_wall_banner[facing=north]"},"minecraft:cyan_wool":{"properties":{},"defaultstate":"minecraft:cyan_wool"},"minecraft:damaged_anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:damaged_anvil[facing=north]"},"minecraft:dandelion":{"properties":{},"defaultstate":"minecraft:dandelion"},"minecraft:dark_oak_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_button[face=wall,facing=north,powered=false]"},"minecraft:dark_oak_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:dark_oak_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:dark_oak_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:dark_oak_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_leaves[distance=7,persistent=false]"},"minecraft:dark_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:dark_oak_log[axis=y]"},"minecraft:dark_oak_planks":{"properties":{},"defaultstate":"minecraft:dark_oak_planks"},"minecraft:dark_oak_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_pressure_plate[powered=false]"},"minecraft:dark_oak_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:dark_oak_sapling[stage=0]"},"minecraft:dark_oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_slab[type=bottom,waterlogged=false]"},"minecraft:dark_oak_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:dark_oak_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:dark_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:dark_oak_wood[axis=y]"},"minecraft:dark_prismarine":{"properties":{},"defaultstate":"minecraft:dark_prismarine"},"minecraft:dark_prismarine_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_prismarine_slab[type=bottom,waterlogged=false]"},"minecraft:dark_prismarine_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_prismarine_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:daylight_detector":{"properties":{"inverted":{"values":["true","false"],"type":"bool"},"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:daylight_detector[inverted=false,power=0]"},"minecraft:dead_brain_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral[waterlogged=true]"},"minecraft:dead_brain_coral_block":{"properties":{},"defaultstate":"minecraft:dead_brain_coral_block"},"minecraft:dead_brain_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral_fan[waterlogged=true]"},"minecraft:dead_brain_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_bubble_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral[waterlogged=true]"},"minecraft:dead_bubble_coral_block":{"properties":{},"defaultstate":"minecraft:dead_bubble_coral_block"},"minecraft:dead_bubble_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral_fan[waterlogged=true]"},"minecraft:dead_bubble_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_bush":{"properties":{},"defaultstate":"minecraft:dead_bush"},"minecraft:dead_fire_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral[waterlogged=true]"},"minecraft:dead_fire_coral_block":{"properties":{},"defaultstate":"minecraft:dead_fire_coral_block"},"minecraft:dead_fire_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral_fan[waterlogged=true]"},"minecraft:dead_fire_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_horn_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral[waterlogged=true]"},"minecraft:dead_horn_coral_block":{"properties":{},"defaultstate":"minecraft:dead_horn_coral_block"},"minecraft:dead_horn_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral_fan[waterlogged=true]"},"minecraft:dead_horn_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_tube_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral[waterlogged=true]"},"minecraft:dead_tube_coral_block":{"properties":{},"defaultstate":"minecraft:dead_tube_coral_block"},"minecraft:dead_tube_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral_fan[waterlogged=true]"},"minecraft:dead_tube_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:detector_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:detector_rail[powered=false,shape=north_south]"},"minecraft:diamond_block":{"properties":{},"defaultstate":"minecraft:diamond_block"},"minecraft:diamond_ore":{"properties":{},"defaultstate":"minecraft:diamond_ore"},"minecraft:diorite":{"properties":{},"defaultstate":"minecraft:diorite"},"minecraft:dirt":{"properties":{},"defaultstate":"minecraft:dirt"},"minecraft:dispenser":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"triggered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dispenser[facing=north,triggered=false]"},"minecraft:dragon_egg":{"properties":{},"defaultstate":"minecraft:dragon_egg"},"minecraft:dragon_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:dragon_head[rotation=0]"},"minecraft:dragon_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:dragon_wall_head[facing=north]"},"minecraft:dried_kelp_block":{"properties":{},"defaultstate":"minecraft:dried_kelp_block"},"minecraft:dropper":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"triggered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dropper[facing=north,triggered=false]"},"minecraft:emerald_block":{"properties":{},"defaultstate":"minecraft:emerald_block"},"minecraft:emerald_ore":{"properties":{},"defaultstate":"minecraft:emerald_ore"},"minecraft:enchanting_table":{"properties":{},"defaultstate":"minecraft:enchanting_table"},"minecraft:end_gateway":{"properties":{},"defaultstate":"minecraft:end_gateway"},"minecraft:end_portal":{"properties":{},"defaultstate":"minecraft:end_portal"},"minecraft:end_portal_frame":{"properties":{"eye":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:end_portal_frame[eye=false,facing=north]"},"minecraft:end_rod":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:end_rod[facing=up]"},"minecraft:end_stone":{"properties":{},"defaultstate":"minecraft:end_stone"},"minecraft:end_stone_bricks":{"properties":{},"defaultstate":"minecraft:end_stone_bricks"},"minecraft:ender_chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:ender_chest[facing=north,waterlogged=false]"},"minecraft:farmland":{"properties":{"moisture":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:farmland[moisture=0]"},"minecraft:fern":{"properties":{},"defaultstate":"minecraft:fern"},"minecraft:fire":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire[age=0,east=false,north=false,south=false,up=false,west=false]"},"minecraft:fire_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral[waterlogged=true]"},"minecraft:fire_coral_block":{"properties":{},"defaultstate":"minecraft:fire_coral_block"},"minecraft:fire_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral_fan[waterlogged=true]"},"minecraft:fire_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:flower_pot":{"properties":{},"defaultstate":"minecraft:flower_pot"},"minecraft:frosted_ice":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:frosted_ice[age=0]"},"minecraft:furnace":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:furnace[facing=north,lit=false]"},"minecraft:glass":{"properties":{},"defaultstate":"minecraft:glass"},"minecraft:glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:glowstone":{"properties":{},"defaultstate":"minecraft:glowstone"},"minecraft:gold_block":{"properties":{},"defaultstate":"minecraft:gold_block"},"minecraft:gold_ore":{"properties":{},"defaultstate":"minecraft:gold_ore"},"minecraft:granite":{"properties":{},"defaultstate":"minecraft:granite"},"minecraft:grass":{"properties":{},"defaultstate":"minecraft:grass"},"minecraft:grass_block":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:grass_block[snowy=false]"},"minecraft:grass_path":{"properties":{},"defaultstate":"minecraft:grass_path"},"minecraft:gravel":{"properties":{},"defaultstate":"minecraft:gravel"},"minecraft:gray_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:gray_banner[rotation=0]"},"minecraft:gray_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:gray_bed[facing=north,occupied=false,part=foot]"},"minecraft:gray_carpet":{"properties":{},"defaultstate":"minecraft:gray_carpet"},"minecraft:gray_concrete":{"properties":{},"defaultstate":"minecraft:gray_concrete"},"minecraft:gray_concrete_powder":{"properties":{},"defaultstate":"minecraft:gray_concrete_powder"},"minecraft:gray_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:gray_glazed_terracotta[facing=north]"},"minecraft:gray_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:gray_shulker_box[facing=up]"},"minecraft:gray_stained_glass":{"properties":{},"defaultstate":"minecraft:gray_stained_glass"},"minecraft:gray_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:gray_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:gray_terracotta":{"properties":{},"defaultstate":"minecraft:gray_terracotta"},"minecraft:gray_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:gray_wall_banner[facing=north]"},"minecraft:gray_wool":{"properties":{},"defaultstate":"minecraft:gray_wool"},"minecraft:green_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:green_banner[rotation=0]"},"minecraft:green_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:green_bed[facing=north,occupied=false,part=foot]"},"minecraft:green_carpet":{"properties":{},"defaultstate":"minecraft:green_carpet"},"minecraft:green_concrete":{"properties":{},"defaultstate":"minecraft:green_concrete"},"minecraft:green_concrete_powder":{"properties":{},"defaultstate":"minecraft:green_concrete_powder"},"minecraft:green_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:green_glazed_terracotta[facing=north]"},"minecraft:green_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:green_shulker_box[facing=up]"},"minecraft:green_stained_glass":{"properties":{},"defaultstate":"minecraft:green_stained_glass"},"minecraft:green_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:green_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:green_terracotta":{"properties":{},"defaultstate":"minecraft:green_terracotta"},"minecraft:green_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:green_wall_banner[facing=north]"},"minecraft:green_wool":{"properties":{},"defaultstate":"minecraft:green_wool"},"minecraft:hay_block":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:hay_block[axis=y]"},"minecraft:heavy_weighted_pressure_plate":{"properties":{"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:heavy_weighted_pressure_plate[power=0]"},"minecraft:hopper":{"properties":{"enabled":{"values":["true","false"],"type":"bool"},"facing":{"values":["down","north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:hopper[enabled=true,facing=down]"},"minecraft:horn_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral[waterlogged=true]"},"minecraft:horn_coral_block":{"properties":{},"defaultstate":"minecraft:horn_coral_block"},"minecraft:horn_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral_fan[waterlogged=true]"},"minecraft:horn_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:ice":{"properties":{},"defaultstate":"minecraft:ice"},"minecraft:infested_chiseled_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_chiseled_stone_bricks"},"minecraft:infested_cobblestone":{"properties":{},"defaultstate":"minecraft:infested_cobblestone"},"minecraft:infested_cracked_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_cracked_stone_bricks"},"minecraft:infested_mossy_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_mossy_stone_bricks"},"minecraft:infested_stone":{"properties":{},"defaultstate":"minecraft:infested_stone"},"minecraft:infested_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_stone_bricks"},"minecraft:iron_bars":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_bars[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:iron_block":{"properties":{},"defaultstate":"minecraft:iron_block"},"minecraft:iron_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:iron_ore":{"properties":{},"defaultstate":"minecraft:iron_ore"},"minecraft:iron_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:jack_o_lantern":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:jack_o_lantern[facing=north]"},"minecraft:jukebox":{"properties":{"has_record":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jukebox[has_record=false]"},"minecraft:jungle_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_button[face=wall,facing=north,powered=false]"},"minecraft:jungle_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:jungle_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:jungle_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:jungle_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_leaves[distance=7,persistent=false]"},"minecraft:jungle_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:jungle_log[axis=y]"},"minecraft:jungle_planks":{"properties":{},"defaultstate":"minecraft:jungle_planks"},"minecraft:jungle_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_pressure_plate[powered=false]"},"minecraft:jungle_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:jungle_sapling[stage=0]"},"minecraft:jungle_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_slab[type=bottom,waterlogged=false]"},"minecraft:jungle_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:jungle_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:jungle_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:jungle_wood[axis=y]"},"minecraft:kelp":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25"],"type":"int"}},"defaultstate":"minecraft:kelp[age=0]"},"minecraft:kelp_plant":{"properties":{},"defaultstate":"minecraft:kelp_plant"},"minecraft:ladder":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:ladder[facing=north,waterlogged=false]"},"minecraft:lapis_block":{"properties":{},"defaultstate":"minecraft:lapis_block"},"minecraft:lapis_ore":{"properties":{},"defaultstate":"minecraft:lapis_ore"},"minecraft:large_fern":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:large_fern[half=lower]"},"minecraft:lava":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:lava[level=0]"},"minecraft:lever":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lever[face=wall,facing=north,powered=false]"},"minecraft:light_blue_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_blue_banner[rotation=0]"},"minecraft:light_blue_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:light_blue_bed[facing=north,occupied=false,part=foot]"},"minecraft:light_blue_carpet":{"properties":{},"defaultstate":"minecraft:light_blue_carpet"},"minecraft:light_blue_concrete":{"properties":{},"defaultstate":"minecraft:light_blue_concrete"},"minecraft:light_blue_concrete_powder":{"properties":{},"defaultstate":"minecraft:light_blue_concrete_powder"},"minecraft:light_blue_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_blue_glazed_terracotta[facing=north]"},"minecraft:light_blue_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:light_blue_shulker_box[facing=up]"},"minecraft:light_blue_stained_glass":{"properties":{},"defaultstate":"minecraft:light_blue_stained_glass"},"minecraft:light_blue_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:light_blue_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:light_blue_terracotta":{"properties":{},"defaultstate":"minecraft:light_blue_terracotta"},"minecraft:light_blue_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_blue_wall_banner[facing=north]"},"minecraft:light_blue_wool":{"properties":{},"defaultstate":"minecraft:light_blue_wool"},"minecraft:light_gray_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_gray_banner[rotation=0]"},"minecraft:light_gray_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:light_gray_bed[facing=north,occupied=false,part=foot]"},"minecraft:light_gray_carpet":{"properties":{},"defaultstate":"minecraft:light_gray_carpet"},"minecraft:light_gray_concrete":{"properties":{},"defaultstate":"minecraft:light_gray_concrete"},"minecraft:light_gray_concrete_powder":{"properties":{},"defaultstate":"minecraft:light_gray_concrete_powder"},"minecraft:light_gray_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_gray_glazed_terracotta[facing=north]"},"minecraft:light_gray_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:light_gray_shulker_box[facing=up]"},"minecraft:light_gray_stained_glass":{"properties":{},"defaultstate":"minecraft:light_gray_stained_glass"},"minecraft:light_gray_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:light_gray_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:light_gray_terracotta":{"properties":{},"defaultstate":"minecraft:light_gray_terracotta"},"minecraft:light_gray_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_gray_wall_banner[facing=north]"},"minecraft:light_gray_wool":{"properties":{},"defaultstate":"minecraft:light_gray_wool"},"minecraft:light_weighted_pressure_plate":{"properties":{"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_weighted_pressure_plate[power=0]"},"minecraft:lilac":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:lilac[half=lower]"},"minecraft:lily_pad":{"properties":{},"defaultstate":"minecraft:lily_pad"},"minecraft:lime_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:lime_banner[rotation=0]"},"minecraft:lime_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:lime_bed[facing=north,occupied=false,part=foot]"},"minecraft:lime_carpet":{"properties":{},"defaultstate":"minecraft:lime_carpet"},"minecraft:lime_concrete":{"properties":{},"defaultstate":"minecraft:lime_concrete"},"minecraft:lime_concrete_powder":{"properties":{},"defaultstate":"minecraft:lime_concrete_powder"},"minecraft:lime_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:lime_glazed_terracotta[facing=north]"},"minecraft:lime_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:lime_shulker_box[facing=up]"},"minecraft:lime_stained_glass":{"properties":{},"defaultstate":"minecraft:lime_stained_glass"},"minecraft:lime_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lime_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:lime_terracotta":{"properties":{},"defaultstate":"minecraft:lime_terracotta"},"minecraft:lime_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:lime_wall_banner[facing=north]"},"minecraft:lime_wool":{"properties":{},"defaultstate":"minecraft:lime_wool"},"minecraft:magenta_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:magenta_banner[rotation=0]"},"minecraft:magenta_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:magenta_bed[facing=north,occupied=false,part=foot]"},"minecraft:magenta_carpet":{"properties":{},"defaultstate":"minecraft:magenta_carpet"},"minecraft:magenta_concrete":{"properties":{},"defaultstate":"minecraft:magenta_concrete"},"minecraft:magenta_concrete_powder":{"properties":{},"defaultstate":"minecraft:magenta_concrete_powder"},"minecraft:magenta_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:magenta_glazed_terracotta[facing=north]"},"minecraft:magenta_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:magenta_shulker_box[facing=up]"},"minecraft:magenta_stained_glass":{"properties":{},"defaultstate":"minecraft:magenta_stained_glass"},"minecraft:magenta_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:magenta_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:magenta_terracotta":{"properties":{},"defaultstate":"minecraft:magenta_terracotta"},"minecraft:magenta_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:magenta_wall_banner[facing=north]"},"minecraft:magenta_wool":{"properties":{},"defaultstate":"minecraft:magenta_wool"},"minecraft:magma_block":{"properties":{},"defaultstate":"minecraft:magma_block"},"minecraft:melon":{"properties":{},"defaultstate":"minecraft:melon"},"minecraft:melon_stem":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:melon_stem[age=0]"},"minecraft:mossy_cobblestone":{"properties":{},"defaultstate":"minecraft:mossy_cobblestone"},"minecraft:mossy_cobblestone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_cobblestone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:mossy_stone_bricks":{"properties":{},"defaultstate":"minecraft:mossy_stone_bricks"},"minecraft:moving_piston":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"type":{"values":["normal","sticky"],"type":"enum"}},"defaultstate":"minecraft:moving_piston[facing=north,type=normal]"},"minecraft:mushroom_stem":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:mycelium":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mycelium[snowy=false]"},"minecraft:nether_brick_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:nether_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_slab[type=bottom,waterlogged=false]"},"minecraft:nether_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:nether_bricks":{"properties":{},"defaultstate":"minecraft:nether_bricks"},"minecraft:nether_portal":{"properties":{"axis":{"values":["x","z"],"type":"enum"}},"defaultstate":"minecraft:nether_portal[axis=x]"},"minecraft:nether_quartz_ore":{"properties":{},"defaultstate":"minecraft:nether_quartz_ore"},"minecraft:nether_wart":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:nether_wart[age=0]"},"minecraft:nether_wart_block":{"properties":{},"defaultstate":"minecraft:nether_wart_block"},"minecraft:netherrack":{"properties":{},"defaultstate":"minecraft:netherrack"},"minecraft:note_block":{"properties":{"instrument":{"values":["harp","basedrum","snare","hat","bass","flute","bell","guitar","chime","xylophone"],"type":"enum"},"note":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24"],"type":"int"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:note_block[instrument=harp,note=0,powered=false]"},"minecraft:oak_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_button[face=wall,facing=north,powered=false]"},"minecraft:oak_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:oak_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:oak_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:oak_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_leaves[distance=7,persistent=false]"},"minecraft:oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:oak_log[axis=y]"},"minecraft:oak_planks":{"properties":{},"defaultstate":"minecraft:oak_planks"},"minecraft:oak_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_pressure_plate[powered=false]"},"minecraft:oak_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:oak_sapling[stage=0]"},"minecraft:oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_slab[type=bottom,waterlogged=false]"},"minecraft:oak_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:oak_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:oak_wood[axis=y]"},"minecraft:observer":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:observer[facing=south,powered=false]"},"minecraft:obsidian":{"properties":{},"defaultstate":"minecraft:obsidian"},"minecraft:orange_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:orange_banner[rotation=0]"},"minecraft:orange_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:orange_bed[facing=north,occupied=false,part=foot]"},"minecraft:orange_carpet":{"properties":{},"defaultstate":"minecraft:orange_carpet"},"minecraft:orange_concrete":{"properties":{},"defaultstate":"minecraft:orange_concrete"},"minecraft:orange_concrete_powder":{"properties":{},"defaultstate":"minecraft:orange_concrete_powder"},"minecraft:orange_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:orange_glazed_terracotta[facing=north]"},"minecraft:orange_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:orange_shulker_box[facing=up]"},"minecraft:orange_stained_glass":{"properties":{},"defaultstate":"minecraft:orange_stained_glass"},"minecraft:orange_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:orange_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:orange_terracotta":{"properties":{},"defaultstate":"minecraft:orange_terracotta"},"minecraft:orange_tulip":{"properties":{},"defaultstate":"minecraft:orange_tulip"},"minecraft:orange_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:orange_wall_banner[facing=north]"},"minecraft:orange_wool":{"properties":{},"defaultstate":"minecraft:orange_wool"},"minecraft:oxeye_daisy":{"properties":{},"defaultstate":"minecraft:oxeye_daisy"},"minecraft:packed_ice":{"properties":{},"defaultstate":"minecraft:packed_ice"},"minecraft:peony":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:peony[half=lower]"},"minecraft:petrified_oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:petrified_oak_slab[type=bottom,waterlogged=false]"},"minecraft:pink_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:pink_banner[rotation=0]"},"minecraft:pink_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:pink_bed[facing=north,occupied=false,part=foot]"},"minecraft:pink_carpet":{"properties":{},"defaultstate":"minecraft:pink_carpet"},"minecraft:pink_concrete":{"properties":{},"defaultstate":"minecraft:pink_concrete"},"minecraft:pink_concrete_powder":{"properties":{},"defaultstate":"minecraft:pink_concrete_powder"},"minecraft:pink_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:pink_glazed_terracotta[facing=north]"},"minecraft:pink_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:pink_shulker_box[facing=up]"},"minecraft:pink_stained_glass":{"properties":{},"defaultstate":"minecraft:pink_stained_glass"},"minecraft:pink_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:pink_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:pink_terracotta":{"properties":{},"defaultstate":"minecraft:pink_terracotta"},"minecraft:pink_tulip":{"properties":{},"defaultstate":"minecraft:pink_tulip"},"minecraft:pink_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:pink_wall_banner[facing=north]"},"minecraft:pink_wool":{"properties":{},"defaultstate":"minecraft:pink_wool"},"minecraft:piston":{"properties":{"extended":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:piston[extended=false,facing=north]"},"minecraft:piston_head":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"short":{"values":["true","false"],"type":"bool"},"type":{"values":["normal","sticky"],"type":"enum"}},"defaultstate":"minecraft:piston_head[facing=north,short=false,type=normal]"},"minecraft:player_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:player_head[rotation=0]"},"minecraft:player_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:player_wall_head[facing=north]"},"minecraft:podzol":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:podzol[snowy=false]"},"minecraft:polished_andesite":{"properties":{},"defaultstate":"minecraft:polished_andesite"},"minecraft:polished_diorite":{"properties":{},"defaultstate":"minecraft:polished_diorite"},"minecraft:polished_granite":{"properties":{},"defaultstate":"minecraft:polished_granite"},"minecraft:poppy":{"properties":{},"defaultstate":"minecraft:poppy"},"minecraft:potatoes":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:potatoes[age=0]"},"minecraft:potted_acacia_sapling":{"properties":{},"defaultstate":"minecraft:potted_acacia_sapling"},"minecraft:potted_allium":{"properties":{},"defaultstate":"minecraft:potted_allium"},"minecraft:potted_azure_bluet":{"properties":{},"defaultstate":"minecraft:potted_azure_bluet"},"minecraft:potted_birch_sapling":{"properties":{},"defaultstate":"minecraft:potted_birch_sapling"},"minecraft:potted_blue_orchid":{"properties":{},"defaultstate":"minecraft:potted_blue_orchid"},"minecraft:potted_brown_mushroom":{"properties":{},"defaultstate":"minecraft:potted_brown_mushroom"},"minecraft:potted_cactus":{"properties":{},"defaultstate":"minecraft:potted_cactus"},"minecraft:potted_dandelion":{"properties":{},"defaultstate":"minecraft:potted_dandelion"},"minecraft:potted_dark_oak_sapling":{"properties":{},"defaultstate":"minecraft:potted_dark_oak_sapling"},"minecraft:potted_dead_bush":{"properties":{},"defaultstate":"minecraft:potted_dead_bush"},"minecraft:potted_fern":{"properties":{},"defaultstate":"minecraft:potted_fern"},"minecraft:potted_jungle_sapling":{"properties":{},"defaultstate":"minecraft:potted_jungle_sapling"},"minecraft:potted_oak_sapling":{"properties":{},"defaultstate":"minecraft:potted_oak_sapling"},"minecraft:potted_orange_tulip":{"properties":{},"defaultstate":"minecraft:potted_orange_tulip"},"minecraft:potted_oxeye_daisy":{"properties":{},"defaultstate":"minecraft:potted_oxeye_daisy"},"minecraft:potted_pink_tulip":{"properties":{},"defaultstate":"minecraft:potted_pink_tulip"},"minecraft:potted_poppy":{"properties":{},"defaultstate":"minecraft:potted_poppy"},"minecraft:potted_red_mushroom":{"properties":{},"defaultstate":"minecraft:potted_red_mushroom"},"minecraft:potted_red_tulip":{"properties":{},"defaultstate":"minecraft:potted_red_tulip"},"minecraft:potted_spruce_sapling":{"properties":{},"defaultstate":"minecraft:potted_spruce_sapling"},"minecraft:potted_white_tulip":{"properties":{},"defaultstate":"minecraft:potted_white_tulip"},"minecraft:powered_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:powered_rail[powered=false,shape=north_south]"},"minecraft:prismarine":{"properties":{},"defaultstate":"minecraft:prismarine"},"minecraft:prismarine_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_brick_slab[type=bottom,waterlogged=false]"},"minecraft:prismarine_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:prismarine_bricks":{"properties":{},"defaultstate":"minecraft:prismarine_bricks"},"minecraft:prismarine_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_slab[type=bottom,waterlogged=false]"},"minecraft:prismarine_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:pumpkin":{"properties":{},"defaultstate":"minecraft:pumpkin"},"minecraft:pumpkin_stem":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:pumpkin_stem[age=0]"},"minecraft:purple_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:purple_banner[rotation=0]"},"minecraft:purple_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:purple_bed[facing=north,occupied=false,part=foot]"},"minecraft:purple_carpet":{"properties":{},"defaultstate":"minecraft:purple_carpet"},"minecraft:purple_concrete":{"properties":{},"defaultstate":"minecraft:purple_concrete"},"minecraft:purple_concrete_powder":{"properties":{},"defaultstate":"minecraft:purple_concrete_powder"},"minecraft:purple_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:purple_glazed_terracotta[facing=north]"},"minecraft:purple_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:purple_shulker_box[facing=up]"},"minecraft:purple_stained_glass":{"properties":{},"defaultstate":"minecraft:purple_stained_glass"},"minecraft:purple_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purple_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:purple_terracotta":{"properties":{},"defaultstate":"minecraft:purple_terracotta"},"minecraft:purple_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:purple_wall_banner[facing=north]"},"minecraft:purple_wool":{"properties":{},"defaultstate":"minecraft:purple_wool"},"minecraft:purpur_block":{"properties":{},"defaultstate":"minecraft:purpur_block"},"minecraft:purpur_pillar":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:purpur_pillar[axis=y]"},"minecraft:purpur_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purpur_slab[type=bottom,waterlogged=false]"},"minecraft:purpur_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purpur_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:quartz_block":{"properties":{},"defaultstate":"minecraft:quartz_block"},"minecraft:quartz_pillar":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:quartz_pillar[axis=y]"},"minecraft:quartz_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:quartz_slab[type=bottom,waterlogged=false]"},"minecraft:quartz_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:quartz_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:rail":{"properties":{"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south","south_east","south_west","north_west","north_east"],"type":"enum"}},"defaultstate":"minecraft:rail[shape=north_south]"},"minecraft:red_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:red_banner[rotation=0]"},"minecraft:red_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:red_bed[facing=north,occupied=false,part=foot]"},"minecraft:red_carpet":{"properties":{},"defaultstate":"minecraft:red_carpet"},"minecraft:red_concrete":{"properties":{},"defaultstate":"minecraft:red_concrete"},"minecraft:red_concrete_powder":{"properties":{},"defaultstate":"minecraft:red_concrete_powder"},"minecraft:red_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:red_glazed_terracotta[facing=north]"},"minecraft:red_mushroom":{"properties":{},"defaultstate":"minecraft:red_mushroom"},"minecraft:red_mushroom_block":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:red_nether_bricks":{"properties":{},"defaultstate":"minecraft:red_nether_bricks"},"minecraft:red_sand":{"properties":{},"defaultstate":"minecraft:red_sand"},"minecraft:red_sandstone":{"properties":{},"defaultstate":"minecraft:red_sandstone"},"minecraft:red_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:red_sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:red_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:red_shulker_box[facing=up]"},"minecraft:red_stained_glass":{"properties":{},"defaultstate":"minecraft:red_stained_glass"},"minecraft:red_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:red_terracotta":{"properties":{},"defaultstate":"minecraft:red_terracotta"},"minecraft:red_tulip":{"properties":{},"defaultstate":"minecraft:red_tulip"},"minecraft:red_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:red_wall_banner[facing=north]"},"minecraft:red_wool":{"properties":{},"defaultstate":"minecraft:red_wool"},"minecraft:redstone_block":{"properties":{},"defaultstate":"minecraft:redstone_block"},"minecraft:redstone_lamp":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_lamp[lit=false]"},"minecraft:redstone_ore":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_ore[lit=false]"},"minecraft:redstone_torch":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_torch[lit=true]"},"minecraft:redstone_wall_torch":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_wall_torch[facing=north,lit=true]"},"minecraft:redstone_wire":{"properties":{"east":{"values":["up","side","none"],"type":"enum"},"north":{"values":["up","side","none"],"type":"enum"},"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"south":{"values":["up","side","none"],"type":"enum"},"west":{"values":["up","side","none"],"type":"enum"}},"defaultstate":"minecraft:redstone_wire[east=none,north=none,power=0,south=none,west=none]"},"minecraft:repeater":{"properties":{"delay":{"values":["1","2","3","4"],"type":"int"},"facing":{"values":["north","south","west","east"],"type":"direction"},"locked":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:repeater[delay=1,facing=north,locked=false,powered=false]"},"minecraft:repeating_command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:repeating_command_block[conditional=false,facing=north]"},"minecraft:rose_bush":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:rose_bush[half=lower]"},"minecraft:sand":{"properties":{},"defaultstate":"minecraft:sand"},"minecraft:sandstone":{"properties":{},"defaultstate":"minecraft:sandstone"},"minecraft:sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:sea_lantern":{"properties":{},"defaultstate":"minecraft:sea_lantern"},"minecraft:sea_pickle":{"properties":{"pickles":{"values":["1","2","3","4"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sea_pickle[pickles=1,waterlogged=true]"},"minecraft:seagrass":{"properties":{},"defaultstate":"minecraft:seagrass"},"minecraft:shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:shulker_box[facing=up]"},"minecraft:sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sign[rotation=0,waterlogged=false]"},"minecraft:skeleton_skull":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:skeleton_skull[rotation=0]"},"minecraft:skeleton_wall_skull":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:skeleton_wall_skull[facing=north]"},"minecraft:slime_block":{"properties":{},"defaultstate":"minecraft:slime_block"},"minecraft:smooth_quartz":{"properties":{},"defaultstate":"minecraft:smooth_quartz"},"minecraft:smooth_red_sandstone":{"properties":{},"defaultstate":"minecraft:smooth_red_sandstone"},"minecraft:smooth_sandstone":{"properties":{},"defaultstate":"minecraft:smooth_sandstone"},"minecraft:smooth_stone":{"properties":{},"defaultstate":"minecraft:smooth_stone"},"minecraft:snow":{"properties":{"layers":{"values":["1","2","3","4","5","6","7","8"],"type":"int"}},"defaultstate":"minecraft:snow[layers=1]"},"minecraft:snow_block":{"properties":{},"defaultstate":"minecraft:snow_block"},"minecraft:soul_sand":{"properties":{},"defaultstate":"minecraft:soul_sand"},"minecraft:spawner":{"properties":{},"defaultstate":"minecraft:spawner"},"minecraft:sponge":{"properties":{},"defaultstate":"minecraft:sponge"},"minecraft:spruce_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_button[face=wall,facing=north,powered=false]"},"minecraft:spruce_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:spruce_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:spruce_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:spruce_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_leaves[distance=7,persistent=false]"},"minecraft:spruce_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:spruce_log[axis=y]"},"minecraft:spruce_planks":{"properties":{},"defaultstate":"minecraft:spruce_planks"},"minecraft:spruce_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_pressure_plate[powered=false]"},"minecraft:spruce_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:spruce_sapling[stage=0]"},"minecraft:spruce_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_slab[type=bottom,waterlogged=false]"},"minecraft:spruce_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:spruce_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:spruce_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:spruce_wood[axis=y]"},"minecraft:sticky_piston":{"properties":{"extended":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:sticky_piston[extended=false,facing=north]"},"minecraft:stone":{"properties":{},"defaultstate":"minecraft:stone"},"minecraft:stone_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_slab[type=bottom,waterlogged=false]"},"minecraft:stone_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:stone_bricks":{"properties":{},"defaultstate":"minecraft:stone_bricks"},"minecraft:stone_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_button[face=wall,facing=north,powered=false]"},"minecraft:stone_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_pressure_plate[powered=false]"},"minecraft:stone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_slab[type=bottom,waterlogged=false]"},"minecraft:stripped_acacia_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_acacia_log[axis=y]"},"minecraft:stripped_acacia_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_acacia_wood[axis=y]"},"minecraft:stripped_birch_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_birch_log[axis=y]"},"minecraft:stripped_birch_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_birch_wood[axis=y]"},"minecraft:stripped_dark_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_dark_oak_log[axis=y]"},"minecraft:stripped_dark_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_dark_oak_wood[axis=y]"},"minecraft:stripped_jungle_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_jungle_log[axis=y]"},"minecraft:stripped_jungle_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_jungle_wood[axis=y]"},"minecraft:stripped_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_oak_log[axis=y]"},"minecraft:stripped_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_oak_wood[axis=y]"},"minecraft:stripped_spruce_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_spruce_log[axis=y]"},"minecraft:stripped_spruce_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_spruce_wood[axis=y]"},"minecraft:structure_block":{"properties":{"mode":{"values":["save","load","corner","data"],"type":"enum"}},"defaultstate":"minecraft:structure_block[mode=save]"},"minecraft:structure_void":{"properties":{},"defaultstate":"minecraft:structure_void"},"minecraft:sugar_cane":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:sugar_cane[age=0]"},"minecraft:sunflower":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:sunflower[half=lower]"},"minecraft:tall_grass":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:tall_grass[half=lower]"},"minecraft:tall_seagrass":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:tall_seagrass[half=lower]"},"minecraft:terracotta":{"properties":{},"defaultstate":"minecraft:terracotta"},"minecraft:tnt":{"properties":{"unstable":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tnt[unstable=false]"},"minecraft:torch":{"properties":{},"defaultstate":"minecraft:torch"},"minecraft:trapped_chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"type":{"values":["single","left","right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:trapped_chest[facing=north,type=single,waterlogged=false]"},"minecraft:tripwire":{"properties":{"attached":{"values":["true","false"],"type":"bool"},"disarmed":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,powered=false,south=false,west=false]"},"minecraft:tripwire_hook":{"properties":{"attached":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tripwire_hook[attached=false,facing=north,powered=false]"},"minecraft:tube_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral[waterlogged=true]"},"minecraft:tube_coral_block":{"properties":{},"defaultstate":"minecraft:tube_coral_block"},"minecraft:tube_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral_fan[waterlogged=true]"},"minecraft:tube_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:turtle_egg":{"properties":{"eggs":{"values":["1","2","3","4"],"type":"int"},"hatch":{"values":["0","1","2"],"type":"int"}},"defaultstate":"minecraft:turtle_egg[eggs=1,hatch=0]"},"minecraft:vine":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:vine[east=false,north=false,south=false,up=false,west=false]"},"minecraft:void_air":{"properties":{},"defaultstate":"minecraft:void_air"},"minecraft:wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:wall_sign[facing=north,waterlogged=false]"},"minecraft:wall_torch":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:wall_torch[facing=north]"},"minecraft:water":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:water[level=0]"},"minecraft:wet_sponge":{"properties":{},"defaultstate":"minecraft:wet_sponge"},"minecraft:wheat":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:wheat[age=0]"},"minecraft:white_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:white_banner[rotation=0]"},"minecraft:white_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:white_bed[facing=north,occupied=false,part=foot]"},"minecraft:white_carpet":{"properties":{},"defaultstate":"minecraft:white_carpet"},"minecraft:white_concrete":{"properties":{},"defaultstate":"minecraft:white_concrete"},"minecraft:white_concrete_powder":{"properties":{},"defaultstate":"minecraft:white_concrete_powder"},"minecraft:white_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:white_glazed_terracotta[facing=north]"},"minecraft:white_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:white_shulker_box[facing=up]"},"minecraft:white_stained_glass":{"properties":{},"defaultstate":"minecraft:white_stained_glass"},"minecraft:white_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:white_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:white_terracotta":{"properties":{},"defaultstate":"minecraft:white_terracotta"},"minecraft:white_tulip":{"properties":{},"defaultstate":"minecraft:white_tulip"},"minecraft:white_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:white_wall_banner[facing=north]"},"minecraft:white_wool":{"properties":{},"defaultstate":"minecraft:white_wool"},"minecraft:wither_skeleton_skull":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:wither_skeleton_skull[rotation=0]"},"minecraft:wither_skeleton_wall_skull":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:wither_skeleton_wall_skull[facing=north]"},"minecraft:yellow_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:yellow_banner[rotation=0]"},"minecraft:yellow_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:yellow_bed[facing=north,occupied=false,part=foot]"},"minecraft:yellow_carpet":{"properties":{},"defaultstate":"minecraft:yellow_carpet"},"minecraft:yellow_concrete":{"properties":{},"defaultstate":"minecraft:yellow_concrete"},"minecraft:yellow_concrete_powder":{"properties":{},"defaultstate":"minecraft:yellow_concrete_powder"},"minecraft:yellow_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:yellow_glazed_terracotta[facing=north]"},"minecraft:yellow_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:yellow_shulker_box[facing=up]"},"minecraft:yellow_stained_glass":{"properties":{},"defaultstate":"minecraft:yellow_stained_glass"},"minecraft:yellow_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:yellow_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:yellow_terracotta":{"properties":{},"defaultstate":"minecraft:yellow_terracotta"},"minecraft:yellow_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:yellow_wall_banner[facing=north]"},"minecraft:yellow_wool":{"properties":{},"defaultstate":"minecraft:yellow_wool"},"minecraft:zombie_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:zombie_head[rotation=0]"},"minecraft:zombie_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:zombie_wall_head[facing=north]"}},"items":["minecraft:acacia_boat","minecraft:acacia_button","minecraft:acacia_door","minecraft:acacia_fence","minecraft:acacia_fence_gate","minecraft:acacia_leaves","minecraft:acacia_log","minecraft:acacia_planks","minecraft:acacia_pressure_plate","minecraft:acacia_sapling","minecraft:acacia_slab","minecraft:acacia_stairs","minecraft:acacia_trapdoor","minecraft:acacia_wood","minecraft:activator_rail","minecraft:air","minecraft:allium","minecraft:andesite","minecraft:anvil","minecraft:apple","minecraft:armor_stand","minecraft:arrow","minecraft:azure_bluet","minecraft:baked_potato","minecraft:barrier","minecraft:bat_spawn_egg","minecraft:beacon","minecraft:bedrock","minecraft:beef","minecraft:beetroot","minecraft:beetroot_seeds","minecraft:beetroot_soup","minecraft:birch_boat","minecraft:birch_button","minecraft:birch_door","minecraft:birch_fence","minecraft:birch_fence_gate","minecraft:birch_leaves","minecraft:birch_log","minecraft:birch_planks","minecraft:birch_pressure_plate","minecraft:birch_sapling","minecraft:birch_slab","minecraft:birch_stairs","minecraft:birch_trapdoor","minecraft:birch_wood","minecraft:black_banner","minecraft:black_bed","minecraft:black_carpet","minecraft:black_concrete","minecraft:black_concrete_powder","minecraft:black_glazed_terracotta","minecraft:black_shulker_box","minecraft:black_stained_glass","minecraft:black_stained_glass_pane","minecraft:black_terracotta","minecraft:black_wool","minecraft:blaze_powder","minecraft:blaze_rod","minecraft:blaze_spawn_egg","minecraft:blue_banner","minecraft:blue_bed","minecraft:blue_carpet","minecraft:blue_concrete","minecraft:blue_concrete_powder","minecraft:blue_glazed_terracotta","minecraft:blue_ice","minecraft:blue_orchid","minecraft:blue_shulker_box","minecraft:blue_stained_glass","minecraft:blue_stained_glass_pane","minecraft:blue_terracotta","minecraft:blue_wool","minecraft:bone","minecraft:bone_block","minecraft:bone_meal","minecraft:book","minecraft:bookshelf","minecraft:bow","minecraft:bowl","minecraft:brain_coral","minecraft:brain_coral_block","minecraft:brain_coral_fan","minecraft:bread","minecraft:brewing_stand","minecraft:brick","minecraft:brick_slab","minecraft:brick_stairs","minecraft:bricks","minecraft:brown_banner","minecraft:brown_bed","minecraft:brown_carpet","minecraft:brown_concrete","minecraft:brown_concrete_powder","minecraft:brown_glazed_terracotta","minecraft:brown_mushroom","minecraft:brown_mushroom_block","minecraft:brown_shulker_box","minecraft:brown_stained_glass","minecraft:brown_stained_glass_pane","minecraft:brown_terracotta","minecraft:brown_wool","minecraft:bubble_coral","minecraft:bubble_coral_block","minecraft:bubble_coral_fan","minecraft:bucket","minecraft:cactus","minecraft:cactus_green","minecraft:cake","minecraft:carrot","minecraft:carrot_on_a_stick","minecraft:carved_pumpkin","minecraft:cauldron","minecraft:cave_spider_spawn_egg","minecraft:chain_command_block","minecraft:chainmail_boots","minecraft:chainmail_chestplate","minecraft:chainmail_helmet","minecraft:chainmail_leggings","minecraft:charcoal","minecraft:chest","minecraft:chest_minecart","minecraft:chicken","minecraft:chicken_spawn_egg","minecraft:chipped_anvil","minecraft:chiseled_quartz_block","minecraft:chiseled_red_sandstone","minecraft:chiseled_sandstone","minecraft:chiseled_stone_bricks","minecraft:chorus_flower","minecraft:chorus_fruit","minecraft:chorus_plant","minecraft:clay","minecraft:clay_ball","minecraft:clock","minecraft:coal","minecraft:coal_block","minecraft:coal_ore","minecraft:coarse_dirt","minecraft:cobblestone","minecraft:cobblestone_slab","minecraft:cobblestone_stairs","minecraft:cobblestone_wall","minecraft:cobweb","minecraft:cocoa_beans","minecraft:cod","minecraft:cod_bucket","minecraft:cod_spawn_egg","minecraft:command_block","minecraft:command_block_minecart","minecraft:comparator","minecraft:compass","minecraft:conduit","minecraft:cooked_beef","minecraft:cooked_chicken","minecraft:cooked_cod","minecraft:cooked_mutton","minecraft:cooked_porkchop","minecraft:cooked_rabbit","minecraft:cooked_salmon","minecraft:cookie","minecraft:cow_spawn_egg","minecraft:cracked_stone_bricks","minecraft:crafting_table","minecraft:creeper_head","minecraft:creeper_spawn_egg","minecraft:cut_red_sandstone","minecraft:cut_sandstone","minecraft:cyan_banner","minecraft:cyan_bed","minecraft:cyan_carpet","minecraft:cyan_concrete","minecraft:cyan_concrete_powder","minecraft:cyan_dye","minecraft:cyan_glazed_terracotta","minecraft:cyan_shulker_box","minecraft:cyan_stained_glass","minecraft:cyan_stained_glass_pane","minecraft:cyan_terracotta","minecraft:cyan_wool","minecraft:damaged_anvil","minecraft:dandelion","minecraft:dandelion_yellow","minecraft:dark_oak_boat","minecraft:dark_oak_button","minecraft:dark_oak_door","minecraft:dark_oak_fence","minecraft:dark_oak_fence_gate","minecraft:dark_oak_leaves","minecraft:dark_oak_log","minecraft:dark_oak_planks","minecraft:dark_oak_pressure_plate","minecraft:dark_oak_sapling","minecraft:dark_oak_slab","minecraft:dark_oak_stairs","minecraft:dark_oak_trapdoor","minecraft:dark_oak_wood","minecraft:dark_prismarine","minecraft:dark_prismarine_slab","minecraft:dark_prismarine_stairs","minecraft:daylight_detector","minecraft:dead_brain_coral","minecraft:dead_brain_coral_block","minecraft:dead_brain_coral_fan","minecraft:dead_bubble_coral","minecraft:dead_bubble_coral_block","minecraft:dead_bubble_coral_fan","minecraft:dead_bush","minecraft:dead_fire_coral","minecraft:dead_fire_coral_block","minecraft:dead_fire_coral_fan","minecraft:dead_horn_coral","minecraft:dead_horn_coral_block","minecraft:dead_horn_coral_fan","minecraft:dead_tube_coral","minecraft:dead_tube_coral_block","minecraft:dead_tube_coral_fan","minecraft:debug_stick","minecraft:detector_rail","minecraft:diamond","minecraft:diamond_axe","minecraft:diamond_block","minecraft:diamond_boots","minecraft:diamond_chestplate","minecraft:diamond_helmet","minecraft:diamond_hoe","minecraft:diamond_horse_armor","minecraft:diamond_leggings","minecraft:diamond_ore","minecraft:diamond_pickaxe","minecraft:diamond_shovel","minecraft:diamond_sword","minecraft:diorite","minecraft:dirt","minecraft:dispenser","minecraft:dolphin_spawn_egg","minecraft:donkey_spawn_egg","minecraft:dragon_breath","minecraft:dragon_egg","minecraft:dragon_head","minecraft:dried_kelp","minecraft:dried_kelp_block","minecraft:dropper","minecraft:drowned_spawn_egg","minecraft:egg","minecraft:elder_guardian_spawn_egg","minecraft:elytra","minecraft:emerald","minecraft:emerald_block","minecraft:emerald_ore","minecraft:enchanted_book","minecraft:enchanted_golden_apple","minecraft:enchanting_table","minecraft:end_crystal","minecraft:end_portal_frame","minecraft:end_rod","minecraft:end_stone","minecraft:end_stone_bricks","minecraft:ender_chest","minecraft:ender_eye","minecraft:ender_pearl","minecraft:enderman_spawn_egg","minecraft:endermite_spawn_egg","minecraft:evoker_spawn_egg","minecraft:experience_bottle","minecraft:farmland","minecraft:feather","minecraft:fermented_spider_eye","minecraft:fern","minecraft:filled_map","minecraft:fire_charge","minecraft:fire_coral","minecraft:fire_coral_block","minecraft:fire_coral_fan","minecraft:firework_rocket","minecraft:firework_star","minecraft:fishing_rod","minecraft:flint","minecraft:flint_and_steel","minecraft:flower_pot","minecraft:furnace","minecraft:furnace_minecart","minecraft:ghast_spawn_egg","minecraft:ghast_tear","minecraft:glass","minecraft:glass_bottle","minecraft:glass_pane","minecraft:glistering_melon_slice","minecraft:glowstone","minecraft:glowstone_dust","minecraft:gold_block","minecraft:gold_ingot","minecraft:gold_nugget","minecraft:gold_ore","minecraft:golden_apple","minecraft:golden_axe","minecraft:golden_boots","minecraft:golden_carrot","minecraft:golden_chestplate","minecraft:golden_helmet","minecraft:golden_hoe","minecraft:golden_horse_armor","minecraft:golden_leggings","minecraft:golden_pickaxe","minecraft:golden_shovel","minecraft:golden_sword","minecraft:granite","minecraft:grass","minecraft:grass_block","minecraft:grass_path","minecraft:gravel","minecraft:gray_banner","minecraft:gray_bed","minecraft:gray_carpet","minecraft:gray_concrete","minecraft:gray_concrete_powder","minecraft:gray_dye","minecraft:gray_glazed_terracotta","minecraft:gray_shulker_box","minecraft:gray_stained_glass","minecraft:gray_stained_glass_pane","minecraft:gray_terracotta","minecraft:gray_wool","minecraft:green_banner","minecraft:green_bed","minecraft:green_carpet","minecraft:green_concrete","minecraft:green_concrete_powder","minecraft:green_glazed_terracotta","minecraft:green_shulker_box","minecraft:green_stained_glass","minecraft:green_stained_glass_pane","minecraft:green_terracotta","minecraft:green_wool","minecraft:guardian_spawn_egg","minecraft:gunpowder","minecraft:hay_block","minecraft:heart_of_the_sea","minecraft:heavy_weighted_pressure_plate","minecraft:hopper","minecraft:hopper_minecart","minecraft:horn_coral","minecraft:horn_coral_block","minecraft:horn_coral_fan","minecraft:horse_spawn_egg","minecraft:husk_spawn_egg","minecraft:ice","minecraft:infested_chiseled_stone_bricks","minecraft:infested_cobblestone","minecraft:infested_cracked_stone_bricks","minecraft:infested_mossy_stone_bricks","minecraft:infested_stone","minecraft:infested_stone_bricks","minecraft:ink_sac","minecraft:iron_axe","minecraft:iron_bars","minecraft:iron_block","minecraft:iron_boots","minecraft:iron_chestplate","minecraft:iron_door","minecraft:iron_helmet","minecraft:iron_hoe","minecraft:iron_horse_armor","minecraft:iron_ingot","minecraft:iron_leggings","minecraft:iron_nugget","minecraft:iron_ore","minecraft:iron_pickaxe","minecraft:iron_shovel","minecraft:iron_sword","minecraft:iron_trapdoor","minecraft:item_frame","minecraft:jack_o_lantern","minecraft:jukebox","minecraft:jungle_boat","minecraft:jungle_button","minecraft:jungle_door","minecraft:jungle_fence","minecraft:jungle_fence_gate","minecraft:jungle_leaves","minecraft:jungle_log","minecraft:jungle_planks","minecraft:jungle_pressure_plate","minecraft:jungle_sapling","minecraft:jungle_slab","minecraft:jungle_stairs","minecraft:jungle_trapdoor","minecraft:jungle_wood","minecraft:kelp","minecraft:knowledge_book","minecraft:ladder","minecraft:lapis_block","minecraft:lapis_lazuli","minecraft:lapis_ore","minecraft:large_fern","minecraft:lava_bucket","minecraft:lead","minecraft:leather","minecraft:leather_boots","minecraft:leather_chestplate","minecraft:leather_helmet","minecraft:leather_leggings","minecraft:lever","minecraft:light_blue_banner","minecraft:light_blue_bed","minecraft:light_blue_carpet","minecraft:light_blue_concrete","minecraft:light_blue_concrete_powder","minecraft:light_blue_dye","minecraft:light_blue_glazed_terracotta","minecraft:light_blue_shulker_box","minecraft:light_blue_stained_glass","minecraft:light_blue_stained_glass_pane","minecraft:light_blue_terracotta","minecraft:light_blue_wool","minecraft:light_gray_banner","minecraft:light_gray_bed","minecraft:light_gray_carpet","minecraft:light_gray_concrete","minecraft:light_gray_concrete_powder","minecraft:light_gray_dye","minecraft:light_gray_glazed_terracotta","minecraft:light_gray_shulker_box","minecraft:light_gray_stained_glass","minecraft:light_gray_stained_glass_pane","minecraft:light_gray_terracotta","minecraft:light_gray_wool","minecraft:light_weighted_pressure_plate","minecraft:lilac","minecraft:lily_pad","minecraft:lime_banner","minecraft:lime_bed","minecraft:lime_carpet","minecraft:lime_concrete","minecraft:lime_concrete_powder","minecraft:lime_dye","minecraft:lime_glazed_terracotta","minecraft:lime_shulker_box","minecraft:lime_stained_glass","minecraft:lime_stained_glass_pane","minecraft:lime_terracotta","minecraft:lime_wool","minecraft:lingering_potion","minecraft:llama_spawn_egg","minecraft:magenta_banner","minecraft:magenta_bed","minecraft:magenta_carpet","minecraft:magenta_concrete","minecraft:magenta_concrete_powder","minecraft:magenta_dye","minecraft:magenta_glazed_terracotta","minecraft:magenta_shulker_box","minecraft:magenta_stained_glass","minecraft:magenta_stained_glass_pane","minecraft:magenta_terracotta","minecraft:magenta_wool","minecraft:magma_block","minecraft:magma_cream","minecraft:magma_cube_spawn_egg","minecraft:map","minecraft:melon","minecraft:melon_seeds","minecraft:melon_slice","minecraft:milk_bucket","minecraft:minecart","minecraft:mooshroom_spawn_egg","minecraft:mossy_cobblestone","minecraft:mossy_cobblestone_wall","minecraft:mossy_stone_bricks","minecraft:mule_spawn_egg","minecraft:mushroom_stem","minecraft:mushroom_stew","minecraft:music_disc_11","minecraft:music_disc_13","minecraft:music_disc_blocks","minecraft:music_disc_cat","minecraft:music_disc_chirp","minecraft:music_disc_far","minecraft:music_disc_mall","minecraft:music_disc_mellohi","minecraft:music_disc_stal","minecraft:music_disc_strad","minecraft:music_disc_wait","minecraft:music_disc_ward","minecraft:mutton","minecraft:mycelium","minecraft:name_tag","minecraft:nautilus_shell","minecraft:nether_brick","minecraft:nether_brick_fence","minecraft:nether_brick_slab","minecraft:nether_brick_stairs","minecraft:nether_bricks","minecraft:nether_quartz_ore","minecraft:nether_star","minecraft:nether_wart","minecraft:nether_wart_block","minecraft:netherrack","minecraft:note_block","minecraft:oak_boat","minecraft:oak_button","minecraft:oak_door","minecraft:oak_fence","minecraft:oak_fence_gate","minecraft:oak_leaves","minecraft:oak_log","minecraft:oak_planks","minecraft:oak_pressure_plate","minecraft:oak_sapling","minecraft:oak_slab","minecraft:oak_stairs","minecraft:oak_trapdoor","minecraft:oak_wood","minecraft:observer","minecraft:obsidian","minecraft:ocelot_spawn_egg","minecraft:orange_banner","minecraft:orange_bed","minecraft:orange_carpet","minecraft:orange_concrete","minecraft:orange_concrete_powder","minecraft:orange_dye","minecraft:orange_glazed_terracotta","minecraft:orange_shulker_box","minecraft:orange_stained_glass","minecraft:orange_stained_glass_pane","minecraft:orange_terracotta","minecraft:orange_tulip","minecraft:orange_wool","minecraft:oxeye_daisy","minecraft:packed_ice","minecraft:painting","minecraft:paper","minecraft:parrot_spawn_egg","minecraft:peony","minecraft:petrified_oak_slab","minecraft:phantom_membrane","minecraft:phantom_spawn_egg","minecraft:pig_spawn_egg","minecraft:pink_banner","minecraft:pink_bed","minecraft:pink_carpet","minecraft:pink_concrete","minecraft:pink_concrete_powder","minecraft:pink_dye","minecraft:pink_glazed_terracotta","minecraft:pink_shulker_box","minecraft:pink_stained_glass","minecraft:pink_stained_glass_pane","minecraft:pink_terracotta","minecraft:pink_tulip","minecraft:pink_wool","minecraft:piston","minecraft:player_head","minecraft:podzol","minecraft:poisonous_potato","minecraft:polar_bear_spawn_egg","minecraft:polished_andesite","minecraft:polished_diorite","minecraft:polished_granite","minecraft:popped_chorus_fruit","minecraft:poppy","minecraft:porkchop","minecraft:potato","minecraft:potion","minecraft:powered_rail","minecraft:prismarine","minecraft:prismarine_brick_slab","minecraft:prismarine_brick_stairs","minecraft:prismarine_bricks","minecraft:prismarine_crystals","minecraft:prismarine_shard","minecraft:prismarine_slab","minecraft:prismarine_stairs","minecraft:pufferfish","minecraft:pufferfish_bucket","minecraft:pufferfish_spawn_egg","minecraft:pumpkin","minecraft:pumpkin_pie","minecraft:pumpkin_seeds","minecraft:purple_banner","minecraft:purple_bed","minecraft:purple_carpet","minecraft:purple_concrete","minecraft:purple_concrete_powder","minecraft:purple_dye","minecraft:purple_glazed_terracotta","minecraft:purple_shulker_box","minecraft:purple_stained_glass","minecraft:purple_stained_glass_pane","minecraft:purple_terracotta","minecraft:purple_wool","minecraft:purpur_block","minecraft:purpur_pillar","minecraft:purpur_slab","minecraft:purpur_stairs","minecraft:quartz","minecraft:quartz_block","minecraft:quartz_pillar","minecraft:quartz_slab","minecraft:quartz_stairs","minecraft:rabbit","minecraft:rabbit_foot","minecraft:rabbit_hide","minecraft:rabbit_spawn_egg","minecraft:rabbit_stew","minecraft:rail","minecraft:red_banner","minecraft:red_bed","minecraft:red_carpet","minecraft:red_concrete","minecraft:red_concrete_powder","minecraft:red_glazed_terracotta","minecraft:red_mushroom","minecraft:red_mushroom_block","minecraft:red_nether_bricks","minecraft:red_sand","minecraft:red_sandstone","minecraft:red_sandstone_slab","minecraft:red_sandstone_stairs","minecraft:red_shulker_box","minecraft:red_stained_glass","minecraft:red_stained_glass_pane","minecraft:red_terracotta","minecraft:red_tulip","minecraft:red_wool","minecraft:redstone","minecraft:redstone_block","minecraft:redstone_lamp","minecraft:redstone_ore","minecraft:redstone_torch","minecraft:repeater","minecraft:repeating_command_block","minecraft:rose_bush","minecraft:rose_red","minecraft:rotten_flesh","minecraft:saddle","minecraft:salmon","minecraft:salmon_bucket","minecraft:salmon_spawn_egg","minecraft:sand","minecraft:sandstone","minecraft:sandstone_slab","minecraft:sandstone_stairs","minecraft:scute","minecraft:sea_lantern","minecraft:sea_pickle","minecraft:seagrass","minecraft:shears","minecraft:sheep_spawn_egg","minecraft:shield","minecraft:shulker_box","minecraft:shulker_shell","minecraft:shulker_spawn_egg","minecraft:sign","minecraft:silverfish_spawn_egg","minecraft:skeleton_horse_spawn_egg","minecraft:skeleton_skull","minecraft:skeleton_spawn_egg","minecraft:slime_ball","minecraft:slime_block","minecraft:slime_spawn_egg","minecraft:smooth_quartz","minecraft:smooth_red_sandstone","minecraft:smooth_sandstone","minecraft:smooth_stone","minecraft:snow","minecraft:snow_block","minecraft:snowball","minecraft:soul_sand","minecraft:spawner","minecraft:spectral_arrow","minecraft:spider_eye","minecraft:spider_spawn_egg","minecraft:splash_potion","minecraft:sponge","minecraft:spruce_boat","minecraft:spruce_button","minecraft:spruce_door","minecraft:spruce_fence","minecraft:spruce_fence_gate","minecraft:spruce_leaves","minecraft:spruce_log","minecraft:spruce_planks","minecraft:spruce_pressure_plate","minecraft:spruce_sapling","minecraft:spruce_slab","minecraft:spruce_stairs","minecraft:spruce_trapdoor","minecraft:spruce_wood","minecraft:squid_spawn_egg","minecraft:stick","minecraft:sticky_piston","minecraft:stone","minecraft:stone_axe","minecraft:stone_brick_slab","minecraft:stone_brick_stairs","minecraft:stone_bricks","minecraft:stone_button","minecraft:stone_hoe","minecraft:stone_pickaxe","minecraft:stone_pressure_plate","minecraft:stone_shovel","minecraft:stone_slab","minecraft:stone_sword","minecraft:stray_spawn_egg","minecraft:string","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood","minecraft:structure_block","minecraft:structure_void","minecraft:sugar","minecraft:sugar_cane","minecraft:sunflower","minecraft:tall_grass","minecraft:terracotta","minecraft:tipped_arrow","minecraft:tnt","minecraft:tnt_minecart","minecraft:torch","minecraft:totem_of_undying","minecraft:trapped_chest","minecraft:trident","minecraft:tripwire_hook","minecraft:tropical_fish","minecraft:tropical_fish_bucket","minecraft:tropical_fish_spawn_egg","minecraft:tube_coral","minecraft:tube_coral_block","minecraft:tube_coral_fan","minecraft:turtle_egg","minecraft:turtle_helmet","minecraft:turtle_spawn_egg","minecraft:vex_spawn_egg","minecraft:villager_spawn_egg","minecraft:vindicator_spawn_egg","minecraft:vine","minecraft:water_bucket","minecraft:wet_sponge","minecraft:wheat","minecraft:wheat_seeds","minecraft:white_banner","minecraft:white_bed","minecraft:white_carpet","minecraft:white_concrete","minecraft:white_concrete_powder","minecraft:white_glazed_terracotta","minecraft:white_shulker_box","minecraft:white_stained_glass","minecraft:white_stained_glass_pane","minecraft:white_terracotta","minecraft:white_tulip","minecraft:white_wool","minecraft:witch_spawn_egg","minecraft:wither_skeleton_skull","minecraft:wither_skeleton_spawn_egg","minecraft:wolf_spawn_egg","minecraft:wooden_axe","minecraft:wooden_hoe","minecraft:wooden_pickaxe","minecraft:wooden_shovel","minecraft:wooden_sword","minecraft:writable_book","minecraft:written_book","minecraft:yellow_banner","minecraft:yellow_bed","minecraft:yellow_carpet","minecraft:yellow_concrete","minecraft:yellow_concrete_powder","minecraft:yellow_glazed_terracotta","minecraft:yellow_shulker_box","minecraft:yellow_stained_glass","minecraft:yellow_stained_glass_pane","minecraft:yellow_terracotta","minecraft:yellow_wool","minecraft:zombie_head","minecraft:zombie_horse_spawn_egg","minecraft:zombie_pigman_spawn_egg","minecraft:zombie_spawn_egg","minecraft:zombie_villager_spawn_egg"],"entities":["minecraft:area_effect_cloud","minecraft:armor_stand","minecraft:arrow","minecraft:bat","minecraft:blaze","minecraft:boat","minecraft:cave_spider","minecraft:chest_minecart","minecraft:chicken","minecraft:cod","minecraft:command_block_minecart","minecraft:cow","minecraft:creeper","minecraft:dolphin","minecraft:donkey","minecraft:dragon_fireball","minecraft:drowned","minecraft:egg","minecraft:elder_guardian","minecraft:end_crystal","minecraft:ender_dragon","minecraft:ender_pearl","minecraft:enderman","minecraft:endermite","minecraft:evoker","minecraft:evoker_fangs","minecraft:experience_bottle","minecraft:experience_orb","minecraft:eye_of_ender","minecraft:falling_block","minecraft:fireball","minecraft:firework_rocket","minecraft:fishing_bobber","minecraft:furnace_minecart","minecraft:ghast","minecraft:giant","minecraft:guardian","minecraft:hopper_minecart","minecraft:horse","minecraft:husk","minecraft:illusioner","minecraft:iron_golem","minecraft:item","minecraft:item_frame","minecraft:leash_knot","minecraft:lightning_bolt","minecraft:llama","minecraft:llama_spit","minecraft:magma_cube","minecraft:minecart","minecraft:mooshroom","minecraft:mule","minecraft:ocelot","minecraft:painting","minecraft:parrot","minecraft:phantom","minecraft:pig","minecraft:player","minecraft:polar_bear","minecraft:potion","minecraft:pufferfish","minecraft:rabbit","minecraft:salmon","minecraft:sheep","minecraft:shulker","minecraft:shulker_bullet","minecraft:silverfish","minecraft:skeleton","minecraft:skeleton_horse","minecraft:slime","minecraft:small_fireball","minecraft:snow_golem","minecraft:snowball","minecraft:spawner_minecart","minecraft:spectral_arrow","minecraft:spider","minecraft:squid","minecraft:stray","minecraft:tnt","minecraft:tnt_minecart","minecraft:trident","minecraft:tropical_fish","minecraft:turtle","minecraft:vex","minecraft:villager","minecraft:vindicator","minecraft:witch","minecraft:wither","minecraft:wither_skeleton","minecraft:wither_skull","minecraft:wolf","minecraft:zombie","minecraft:zombie_horse","minecraft:zombie_pigman","minecraft:zombie_villager"],"biomes":["minecraft:badlands","minecraft:badlands_plateau","minecraft:beach","minecraft:birch_forest","minecraft:birch_forest_hills","minecraft:cold_ocean","minecraft:dark_forest","minecraft:dark_forest_hills","minecraft:deep_cold_ocean","minecraft:deep_frozen_ocean","minecraft:deep_lukewarm_ocean","minecraft:deep_ocean","minecraft:deep_warm_ocean","minecraft:desert","minecraft:desert_hills","minecraft:desert_lakes","minecraft:end_barrens","minecraft:end_highlands","minecraft:end_midlands","minecraft:eroded_badlands","minecraft:flower_forest","minecraft:forest","minecraft:frozen_ocean","minecraft:frozen_river","minecraft:giant_spruce_taiga","minecraft:giant_spruce_taiga_hills","minecraft:giant_tree_taiga","minecraft:giant_tree_taiga_hills","minecraft:gravelly_mountains","minecraft:ice_spikes","minecraft:jungle","minecraft:jungle_edge","minecraft:jungle_hills","minecraft:lukewarm_ocean","minecraft:modified_badlands_plateau","minecraft:modified_gravelly_mountains","minecraft:modified_jungle","minecraft:modified_jungle_edge","minecraft:modified_wooded_badlands_plateau","minecraft:mountain_edge","minecraft:mountains","minecraft:mushroom_field_shore","minecraft:mushroom_fields","minecraft:nether","minecraft:ocean","minecraft:plains","minecraft:river","minecraft:savanna","minecraft:savanna_plateau","minecraft:shattered_savanna","minecraft:shattered_savanna_plateau","minecraft:small_end_islands","minecraft:snowy_beach","minecraft:snowy_mountains","minecraft:snowy_taiga","minecraft:snowy_taiga_hills","minecraft:snowy_taiga_mountains","minecraft:snowy_tundra","minecraft:stone_shore","minecraft:sunflower_plains","minecraft:swamp","minecraft:swamp_hills","minecraft:taiga","minecraft:taiga_hills","minecraft:taiga_mountains","minecraft:tall_birch_forest","minecraft:tall_birch_hills","minecraft:the_end","minecraft:the_void","minecraft:warm_ocean","minecraft:wooded_badlands_plateau","minecraft:wooded_hills","minecraft:wooded_mountains"],"blocktags":{"minecraft:wool":["minecraft:white_wool","minecraft:orange_wool","minecraft:magenta_wool","minecraft:light_blue_wool","minecraft:yellow_wool","minecraft:lime_wool","minecraft:pink_wool","minecraft:gray_wool","minecraft:light_gray_wool","minecraft:cyan_wool","minecraft:purple_wool","minecraft:blue_wool","minecraft:brown_wool","minecraft:green_wool","minecraft:red_wool","minecraft:black_wool"],"minecraft:planks":["minecraft:oak_planks","minecraft:spruce_planks","minecraft:birch_planks","minecraft:jungle_planks","minecraft:acacia_planks","minecraft:dark_oak_planks"],"minecraft:stone_bricks":["minecraft:stone_bricks","minecraft:mossy_stone_bricks","minecraft:cracked_stone_bricks","minecraft:chiseled_stone_bricks"],"minecraft:wooden_buttons":["minecraft:oak_button","minecraft:spruce_button","minecraft:birch_button","minecraft:jungle_button","minecraft:acacia_button","minecraft:dark_oak_button"],"minecraft:buttons":["minecraft:stone_button","minecraft:oak_button","minecraft:spruce_button","minecraft:birch_button","minecraft:jungle_button","minecraft:acacia_button","minecraft:dark_oak_button"],"minecraft:carpets":["minecraft:white_carpet","minecraft:orange_carpet","minecraft:magenta_carpet","minecraft:light_blue_carpet","minecraft:yellow_carpet","minecraft:lime_carpet","minecraft:pink_carpet","minecraft:gray_carpet","minecraft:light_gray_carpet","minecraft:cyan_carpet","minecraft:purple_carpet","minecraft:blue_carpet","minecraft:brown_carpet","minecraft:green_carpet","minecraft:red_carpet","minecraft:black_carpet"],"minecraft:wooden_doors":["minecraft:oak_door","minecraft:spruce_door","minecraft:birch_door","minecraft:jungle_door","minecraft:acacia_door","minecraft:dark_oak_door"],"minecraft:wooden_stairs":["minecraft:oak_stairs","minecraft:spruce_stairs","minecraft:birch_stairs","minecraft:jungle_stairs","minecraft:acacia_stairs","minecraft:dark_oak_stairs"],"minecraft:wooden_slabs":["minecraft:oak_slab","minecraft:spruce_slab","minecraft:birch_slab","minecraft:jungle_slab","minecraft:acacia_slab","minecraft:dark_oak_slab"],"minecraft:doors":["minecraft:iron_door","minecraft:oak_door","minecraft:spruce_door","minecraft:birch_door","minecraft:jungle_door","minecraft:acacia_door","minecraft:dark_oak_door"],"minecraft:saplings":["minecraft:oak_sapling","minecraft:spruce_sapling","minecraft:birch_sapling","minecraft:jungle_sapling","minecraft:acacia_sapling","minecraft:dark_oak_sapling"],"minecraft:dark_oak_logs":["minecraft:dark_oak_log","minecraft:dark_oak_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood"],"minecraft:oak_logs":["minecraft:oak_log","minecraft:oak_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood"],"minecraft:acacia_logs":["minecraft:acacia_log","minecraft:acacia_wood","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood"],"minecraft:birch_logs":["minecraft:birch_log","minecraft:birch_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood"],"minecraft:jungle_logs":["minecraft:jungle_log","minecraft:jungle_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood"],"minecraft:spruce_logs":["minecraft:spruce_log","minecraft:spruce_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood"],"minecraft:anvil":["minecraft:anvil","minecraft:chipped_anvil","minecraft:damaged_anvil"],"minecraft:enderman_holdable":["minecraft:grass_block","minecraft:dirt","minecraft:coarse_dirt","minecraft:podzol","minecraft:sand","minecraft:red_sand","minecraft:gravel","minecraft:dandelion","minecraft:poppy","minecraft:blue_orchid","minecraft:allium","minecraft:azure_bluet","minecraft:red_tulip","minecraft:orange_tulip","minecraft:white_tulip","minecraft:pink_tulip","minecraft:oxeye_daisy","minecraft:brown_mushroom","minecraft:red_mushroom","minecraft:tnt","minecraft:cactus","minecraft:clay","minecraft:pumpkin","minecraft:carved_pumpkin","minecraft:melon","minecraft:mycelium","minecraft:netherrack"],"minecraft:flower_pots":["minecraft:flower_pot","minecraft:potted_poppy","minecraft:potted_blue_orchid","minecraft:potted_allium","minecraft:potted_azure_bluet","minecraft:potted_red_tulip","minecraft:potted_orange_tulip","minecraft:potted_white_tulip","minecraft:potted_pink_tulip","minecraft:potted_oxeye_daisy","minecraft:potted_dandelion","minecraft:potted_oak_sapling","minecraft:potted_spruce_sapling","minecraft:potted_birch_sapling","minecraft:potted_jungle_sapling","minecraft:potted_acacia_sapling","minecraft:potted_dark_oak_sapling","minecraft:potted_red_mushroom","minecraft:potted_brown_mushroom","minecraft:potted_dead_bush","minecraft:potted_fern","minecraft:potted_cactus"],"minecraft:banners":["minecraft:white_banner","minecraft:orange_banner","minecraft:magenta_banner","minecraft:light_blue_banner","minecraft:yellow_banner","minecraft:lime_banner","minecraft:pink_banner","minecraft:gray_banner","minecraft:light_gray_banner","minecraft:cyan_banner","minecraft:purple_banner","minecraft:blue_banner","minecraft:brown_banner","minecraft:green_banner","minecraft:red_banner","minecraft:black_banner","minecraft:white_wall_banner","minecraft:orange_wall_banner","minecraft:magenta_wall_banner","minecraft:light_blue_wall_banner","minecraft:yellow_wall_banner","minecraft:lime_wall_banner","minecraft:pink_wall_banner","minecraft:gray_wall_banner","minecraft:light_gray_wall_banner","minecraft:cyan_wall_banner","minecraft:purple_wall_banner","minecraft:blue_wall_banner","minecraft:brown_wall_banner","minecraft:green_wall_banner","minecraft:red_wall_banner","minecraft:black_wall_banner"],"minecraft:wooden_pressure_plates":["minecraft:oak_pressure_plate","minecraft:spruce_pressure_plate","minecraft:birch_pressure_plate","minecraft:jungle_pressure_plate","minecraft:acacia_pressure_plate","minecraft:dark_oak_pressure_plate"],"minecraft:stairs":["minecraft:oak_stairs","minecraft:cobblestone_stairs","minecraft:spruce_stairs","minecraft:sandstone_stairs","minecraft:acacia_stairs","minecraft:jungle_stairs","minecraft:birch_stairs","minecraft:dark_oak_stairs","minecraft:nether_brick_stairs","minecraft:stone_brick_stairs","minecraft:brick_stairs","minecraft:purpur_stairs","minecraft:quartz_stairs","minecraft:red_sandstone_stairs","minecraft:prismarine_brick_stairs","minecraft:prismarine_stairs","minecraft:dark_prismarine_stairs"],"minecraft:slabs":["minecraft:stone_slab","minecraft:stone_brick_slab","minecraft:sandstone_slab","minecraft:acacia_slab","minecraft:birch_slab","minecraft:dark_oak_slab","minecraft:jungle_slab","minecraft:oak_slab","minecraft:spruce_slab","minecraft:purpur_slab","minecraft:quartz_slab","minecraft:red_sandstone_slab","minecraft:brick_slab","minecraft:cobblestone_slab","minecraft:nether_brick_slab","minecraft:petrified_oak_slab","minecraft:prismarine_slab","minecraft:prismarine_brick_slab","minecraft:dark_prismarine_slab"],"minecraft:coral_plants":["minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral"],"minecraft:corals":["minecraft:tube_coral_fan","minecraft:brain_coral_fan","minecraft:bubble_coral_fan","minecraft:fire_coral_fan","minecraft:horn_coral_fan","minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral"],"minecraft:wall_corals":["minecraft:tube_coral_wall_fan","minecraft:brain_coral_wall_fan","minecraft:bubble_coral_wall_fan","minecraft:fire_coral_wall_fan","minecraft:horn_coral_wall_fan"],"minecraft:sand":["minecraft:sand","minecraft:red_sand"],"minecraft:rails":["minecraft:rail","minecraft:powered_rail","minecraft:detector_rail","minecraft:activator_rail"],"minecraft:coral_blocks":["minecraft:tube_coral_block","minecraft:brain_coral_block","minecraft:bubble_coral_block","minecraft:fire_coral_block","minecraft:horn_coral_block"],"minecraft:ice":["minecraft:ice","minecraft:packed_ice","minecraft:blue_ice","minecraft:frosted_ice"],"minecraft:valid_spawn":["minecraft:grass_block","minecraft:podzol"],"minecraft:leaves":["minecraft:jungle_leaves","minecraft:oak_leaves","minecraft:spruce_leaves","minecraft:dark_oak_leaves","minecraft:acacia_leaves","minecraft:birch_leaves"],"minecraft:impermeable":["minecraft:glass","minecraft:white_stained_glass","minecraft:orange_stained_glass","minecraft:magenta_stained_glass","minecraft:light_blue_stained_glass","minecraft:yellow_stained_glass","minecraft:lime_stained_glass","minecraft:pink_stained_glass","minecraft:gray_stained_glass","minecraft:light_gray_stained_glass","minecraft:cyan_stained_glass","minecraft:purple_stained_glass","minecraft:blue_stained_glass","minecraft:brown_stained_glass","minecraft:green_stained_glass","minecraft:red_stained_glass","minecraft:black_stained_glass"],"minecraft:wooden_trapdoors":["minecraft:acacia_trapdoor","minecraft:birch_trapdoor","minecraft:dark_oak_trapdoor","minecraft:jungle_trapdoor","minecraft:oak_trapdoor","minecraft:spruce_trapdoor"],"minecraft:trapdoors":["minecraft:iron_trapdoor","minecraft:acacia_trapdoor","minecraft:birch_trapdoor","minecraft:dark_oak_trapdoor","minecraft:jungle_trapdoor","minecraft:oak_trapdoor","minecraft:spruce_trapdoor"],"minecraft:underwater_bonemeals":["minecraft:seagrass","minecraft:tube_coral_fan","minecraft:brain_coral_fan","minecraft:bubble_coral_fan","minecraft:fire_coral_fan","minecraft:horn_coral_fan","minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral","minecraft:tube_coral_wall_fan","minecraft:brain_coral_wall_fan","minecraft:bubble_coral_wall_fan","minecraft:fire_coral_wall_fan","minecraft:horn_coral_wall_fan"],"minecraft:logs":["minecraft:dark_oak_log","minecraft:dark_oak_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood","minecraft:oak_log","minecraft:oak_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood","minecraft:acacia_log","minecraft:acacia_wood","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood","minecraft:birch_log","minecraft:birch_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood","minecraft:jungle_log","minecraft:jungle_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood","minecraft:spruce_log","minecraft:spruce_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood"]},"itemtags":{"minecraft:banners":["minecraft:white_banner","minecraft:orange_banner","minecraft:magenta_banner","minecraft:light_blue_banner","minecraft:yellow_banner","minecraft:lime_banner","minecraft:pink_banner","minecraft:gray_banner","minecraft:light_gray_banner","minecraft:cyan_banner","minecraft:purple_banner","minecraft:blue_banner","minecraft:brown_banner","minecraft:green_banner","minecraft:red_banner","minecraft:black_banner"],"minecraft:boats":["minecraft:oak_boat","minecraft:spruce_boat","minecraft:birch_boat","minecraft:jungle_boat","minecraft:acacia_boat","minecraft:dark_oak_boat"],"minecraft:fishes":["minecraft:cod","minecraft:cooked_cod","minecraft:salmon","minecraft:cooked_salmon","minecraft:pufferfish","minecraft:tropical_fish"]},"entitytags":{}} \ No newline at end of file diff --git a/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1963.json b/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1963.json new file mode 100644 index 000000000..f99217273 --- /dev/null +++ b/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1963.json @@ -0,0 +1 @@ +{"blocks":{"minecraft:acacia_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_button[face=wall,facing=north,powered=false]"},"minecraft:acacia_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:acacia_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:acacia_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:acacia_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_leaves[distance=7,persistent=false]"},"minecraft:acacia_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:acacia_log[axis=y]"},"minecraft:acacia_planks":{"properties":{},"defaultstate":"minecraft:acacia_planks"},"minecraft:acacia_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_pressure_plate[powered=false]"},"minecraft:acacia_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:acacia_sapling[stage=0]"},"minecraft:acacia_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_sign[rotation=0,waterlogged=false]"},"minecraft:acacia_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_slab[type=bottom,waterlogged=false]"},"minecraft:acacia_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:acacia_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:acacia_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_wall_sign[facing=north,waterlogged=false]"},"minecraft:acacia_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:acacia_wood[axis=y]"},"minecraft:activator_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:activator_rail[powered=false,shape=north_south]"},"minecraft:air":{"properties":{},"defaultstate":"minecraft:air"},"minecraft:allium":{"properties":{},"defaultstate":"minecraft:allium"},"minecraft:andesite":{"properties":{},"defaultstate":"minecraft:andesite"},"minecraft:andesite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:andesite_slab[type=bottom,waterlogged=false]"},"minecraft:andesite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:andesite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:andesite_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:andesite_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:anvil[facing=north]"},"minecraft:attached_melon_stem":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:attached_melon_stem[facing=north]"},"minecraft:attached_pumpkin_stem":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:attached_pumpkin_stem[facing=north]"},"minecraft:azure_bluet":{"properties":{},"defaultstate":"minecraft:azure_bluet"},"minecraft:bamboo":{"properties":{"age":{"values":["0","1"],"type":"int"},"leaves":{"values":["none","small","large"],"type":"enum"},"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:bamboo[age=0,leaves=none,stage=0]"},"minecraft:bamboo_sapling":{"properties":{},"defaultstate":"minecraft:bamboo_sapling"},"minecraft:barrel":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"open":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:barrel[facing=north,open=false]"},"minecraft:barrier":{"properties":{},"defaultstate":"minecraft:barrier"},"minecraft:beacon":{"properties":{},"defaultstate":"minecraft:beacon"},"minecraft:bedrock":{"properties":{},"defaultstate":"minecraft:bedrock"},"minecraft:beetroots":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:beetroots[age=0]"},"minecraft:bell":{"properties":{"attachment":{"values":["floor","ceiling","single_wall","double_wall"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:bell[attachment=floor,facing=north]"},"minecraft:birch_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_button[face=wall,facing=north,powered=false]"},"minecraft:birch_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:birch_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:birch_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:birch_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_leaves[distance=7,persistent=false]"},"minecraft:birch_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:birch_log[axis=y]"},"minecraft:birch_planks":{"properties":{},"defaultstate":"minecraft:birch_planks"},"minecraft:birch_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_pressure_plate[powered=false]"},"minecraft:birch_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:birch_sapling[stage=0]"},"minecraft:birch_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_sign[rotation=0,waterlogged=false]"},"minecraft:birch_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_slab[type=bottom,waterlogged=false]"},"minecraft:birch_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:birch_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:birch_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_wall_sign[facing=north,waterlogged=false]"},"minecraft:birch_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:birch_wood[axis=y]"},"minecraft:black_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:black_banner[rotation=0]"},"minecraft:black_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:black_bed[facing=north,occupied=false,part=foot]"},"minecraft:black_carpet":{"properties":{},"defaultstate":"minecraft:black_carpet"},"minecraft:black_concrete":{"properties":{},"defaultstate":"minecraft:black_concrete"},"minecraft:black_concrete_powder":{"properties":{},"defaultstate":"minecraft:black_concrete_powder"},"minecraft:black_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:black_glazed_terracotta[facing=north]"},"minecraft:black_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:black_shulker_box[facing=up]"},"minecraft:black_stained_glass":{"properties":{},"defaultstate":"minecraft:black_stained_glass"},"minecraft:black_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:black_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:black_terracotta":{"properties":{},"defaultstate":"minecraft:black_terracotta"},"minecraft:black_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:black_wall_banner[facing=north]"},"minecraft:black_wool":{"properties":{},"defaultstate":"minecraft:black_wool"},"minecraft:blast_furnace":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:blast_furnace[facing=north,lit=false]"},"minecraft:blue_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:blue_banner[rotation=0]"},"minecraft:blue_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:blue_bed[facing=north,occupied=false,part=foot]"},"minecraft:blue_carpet":{"properties":{},"defaultstate":"minecraft:blue_carpet"},"minecraft:blue_concrete":{"properties":{},"defaultstate":"minecraft:blue_concrete"},"minecraft:blue_concrete_powder":{"properties":{},"defaultstate":"minecraft:blue_concrete_powder"},"minecraft:blue_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:blue_glazed_terracotta[facing=north]"},"minecraft:blue_ice":{"properties":{},"defaultstate":"minecraft:blue_ice"},"minecraft:blue_orchid":{"properties":{},"defaultstate":"minecraft:blue_orchid"},"minecraft:blue_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:blue_shulker_box[facing=up]"},"minecraft:blue_stained_glass":{"properties":{},"defaultstate":"minecraft:blue_stained_glass"},"minecraft:blue_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:blue_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:blue_terracotta":{"properties":{},"defaultstate":"minecraft:blue_terracotta"},"minecraft:blue_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:blue_wall_banner[facing=north]"},"minecraft:blue_wool":{"properties":{},"defaultstate":"minecraft:blue_wool"},"minecraft:bone_block":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:bone_block[axis=y]"},"minecraft:bookshelf":{"properties":{},"defaultstate":"minecraft:bookshelf"},"minecraft:brain_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral[waterlogged=true]"},"minecraft:brain_coral_block":{"properties":{},"defaultstate":"minecraft:brain_coral_block"},"minecraft:brain_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral_fan[waterlogged=true]"},"minecraft:brain_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:brewing_stand":{"properties":{"has_bottle_0":{"values":["true","false"],"type":"bool"},"has_bottle_1":{"values":["true","false"],"type":"bool"},"has_bottle_2":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]"},"minecraft:brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_slab[type=bottom,waterlogged=false]"},"minecraft:brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:bricks":{"properties":{},"defaultstate":"minecraft:bricks"},"minecraft:brown_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:brown_banner[rotation=0]"},"minecraft:brown_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:brown_bed[facing=north,occupied=false,part=foot]"},"minecraft:brown_carpet":{"properties":{},"defaultstate":"minecraft:brown_carpet"},"minecraft:brown_concrete":{"properties":{},"defaultstate":"minecraft:brown_concrete"},"minecraft:brown_concrete_powder":{"properties":{},"defaultstate":"minecraft:brown_concrete_powder"},"minecraft:brown_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:brown_glazed_terracotta[facing=north]"},"minecraft:brown_mushroom":{"properties":{},"defaultstate":"minecraft:brown_mushroom"},"minecraft:brown_mushroom_block":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:brown_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:brown_shulker_box[facing=up]"},"minecraft:brown_stained_glass":{"properties":{},"defaultstate":"minecraft:brown_stained_glass"},"minecraft:brown_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brown_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:brown_terracotta":{"properties":{},"defaultstate":"minecraft:brown_terracotta"},"minecraft:brown_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:brown_wall_banner[facing=north]"},"minecraft:brown_wool":{"properties":{},"defaultstate":"minecraft:brown_wool"},"minecraft:bubble_column":{"properties":{"drag":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_column[drag=true]"},"minecraft:bubble_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral[waterlogged=true]"},"minecraft:bubble_coral_block":{"properties":{},"defaultstate":"minecraft:bubble_coral_block"},"minecraft:bubble_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral_fan[waterlogged=true]"},"minecraft:bubble_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:cactus":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:cactus[age=0]"},"minecraft:cake":{"properties":{"bites":{"values":["0","1","2","3","4","5","6"],"type":"int"}},"defaultstate":"minecraft:cake[bites=0]"},"minecraft:campfire":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"},"signal_fire":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:campfire[facing=north,lit=true,signal_fire=false,waterlogged=false]"},"minecraft:carrots":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:carrots[age=0]"},"minecraft:cartography_table":{"properties":{},"defaultstate":"minecraft:cartography_table"},"minecraft:carved_pumpkin":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:carved_pumpkin[facing=north]"},"minecraft:cauldron":{"properties":{"level":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:cauldron[level=0]"},"minecraft:cave_air":{"properties":{},"defaultstate":"minecraft:cave_air"},"minecraft:chain_command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:chain_command_block[conditional=false,facing=north]"},"minecraft:chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"type":{"values":["single","left","right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:chest[facing=north,type=single,waterlogged=false]"},"minecraft:chipped_anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:chipped_anvil[facing=north]"},"minecraft:chiseled_quartz_block":{"properties":{},"defaultstate":"minecraft:chiseled_quartz_block"},"minecraft:chiseled_red_sandstone":{"properties":{},"defaultstate":"minecraft:chiseled_red_sandstone"},"minecraft:chiseled_sandstone":{"properties":{},"defaultstate":"minecraft:chiseled_sandstone"},"minecraft:chiseled_stone_bricks":{"properties":{},"defaultstate":"minecraft:chiseled_stone_bricks"},"minecraft:chorus_flower":{"properties":{"age":{"values":["0","1","2","3","4","5"],"type":"int"}},"defaultstate":"minecraft:chorus_flower[age=0]"},"minecraft:chorus_plant":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]"},"minecraft:clay":{"properties":{},"defaultstate":"minecraft:clay"},"minecraft:coal_block":{"properties":{},"defaultstate":"minecraft:coal_block"},"minecraft:coal_ore":{"properties":{},"defaultstate":"minecraft:coal_ore"},"minecraft:coarse_dirt":{"properties":{},"defaultstate":"minecraft:coarse_dirt"},"minecraft:cobblestone":{"properties":{},"defaultstate":"minecraft:cobblestone"},"minecraft:cobblestone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_slab[type=bottom,waterlogged=false]"},"minecraft:cobblestone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:cobblestone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:cobweb":{"properties":{},"defaultstate":"minecraft:cobweb"},"minecraft:cocoa":{"properties":{"age":{"values":["0","1","2"],"type":"int"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cocoa[age=0,facing=north]"},"minecraft:command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:command_block[conditional=false,facing=north]"},"minecraft:comparator":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"mode":{"values":["compare","subtract"],"type":"enum"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:comparator[facing=north,mode=compare,powered=false]"},"minecraft:composter":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8"],"type":"int"}},"defaultstate":"minecraft:composter[level=0]"},"minecraft:conduit":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:conduit[waterlogged=true]"},"minecraft:cornflower":{"properties":{},"defaultstate":"minecraft:cornflower"},"minecraft:cracked_stone_bricks":{"properties":{},"defaultstate":"minecraft:cracked_stone_bricks"},"minecraft:crafting_table":{"properties":{},"defaultstate":"minecraft:crafting_table"},"minecraft:creeper_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:creeper_head[rotation=0]"},"minecraft:creeper_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:creeper_wall_head[facing=north]"},"minecraft:cut_red_sandstone":{"properties":{},"defaultstate":"minecraft:cut_red_sandstone"},"minecraft:cut_red_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cut_red_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:cut_sandstone":{"properties":{},"defaultstate":"minecraft:cut_sandstone"},"minecraft:cut_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cut_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:cyan_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:cyan_banner[rotation=0]"},"minecraft:cyan_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:cyan_bed[facing=north,occupied=false,part=foot]"},"minecraft:cyan_carpet":{"properties":{},"defaultstate":"minecraft:cyan_carpet"},"minecraft:cyan_concrete":{"properties":{},"defaultstate":"minecraft:cyan_concrete"},"minecraft:cyan_concrete_powder":{"properties":{},"defaultstate":"minecraft:cyan_concrete_powder"},"minecraft:cyan_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cyan_glazed_terracotta[facing=north]"},"minecraft:cyan_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:cyan_shulker_box[facing=up]"},"minecraft:cyan_stained_glass":{"properties":{},"defaultstate":"minecraft:cyan_stained_glass"},"minecraft:cyan_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cyan_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:cyan_terracotta":{"properties":{},"defaultstate":"minecraft:cyan_terracotta"},"minecraft:cyan_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cyan_wall_banner[facing=north]"},"minecraft:cyan_wool":{"properties":{},"defaultstate":"minecraft:cyan_wool"},"minecraft:damaged_anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:damaged_anvil[facing=north]"},"minecraft:dandelion":{"properties":{},"defaultstate":"minecraft:dandelion"},"minecraft:dark_oak_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_button[face=wall,facing=north,powered=false]"},"minecraft:dark_oak_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:dark_oak_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:dark_oak_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:dark_oak_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_leaves[distance=7,persistent=false]"},"minecraft:dark_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:dark_oak_log[axis=y]"},"minecraft:dark_oak_planks":{"properties":{},"defaultstate":"minecraft:dark_oak_planks"},"minecraft:dark_oak_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_pressure_plate[powered=false]"},"minecraft:dark_oak_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:dark_oak_sapling[stage=0]"},"minecraft:dark_oak_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_sign[rotation=0,waterlogged=false]"},"minecraft:dark_oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_slab[type=bottom,waterlogged=false]"},"minecraft:dark_oak_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:dark_oak_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:dark_oak_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_wall_sign[facing=north,waterlogged=false]"},"minecraft:dark_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:dark_oak_wood[axis=y]"},"minecraft:dark_prismarine":{"properties":{},"defaultstate":"minecraft:dark_prismarine"},"minecraft:dark_prismarine_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_prismarine_slab[type=bottom,waterlogged=false]"},"minecraft:dark_prismarine_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_prismarine_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:daylight_detector":{"properties":{"inverted":{"values":["true","false"],"type":"bool"},"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:daylight_detector[inverted=false,power=0]"},"minecraft:dead_brain_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral[waterlogged=true]"},"minecraft:dead_brain_coral_block":{"properties":{},"defaultstate":"minecraft:dead_brain_coral_block"},"minecraft:dead_brain_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral_fan[waterlogged=true]"},"minecraft:dead_brain_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_bubble_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral[waterlogged=true]"},"minecraft:dead_bubble_coral_block":{"properties":{},"defaultstate":"minecraft:dead_bubble_coral_block"},"minecraft:dead_bubble_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral_fan[waterlogged=true]"},"minecraft:dead_bubble_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_bush":{"properties":{},"defaultstate":"minecraft:dead_bush"},"minecraft:dead_fire_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral[waterlogged=true]"},"minecraft:dead_fire_coral_block":{"properties":{},"defaultstate":"minecraft:dead_fire_coral_block"},"minecraft:dead_fire_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral_fan[waterlogged=true]"},"minecraft:dead_fire_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_horn_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral[waterlogged=true]"},"minecraft:dead_horn_coral_block":{"properties":{},"defaultstate":"minecraft:dead_horn_coral_block"},"minecraft:dead_horn_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral_fan[waterlogged=true]"},"minecraft:dead_horn_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_tube_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral[waterlogged=true]"},"minecraft:dead_tube_coral_block":{"properties":{},"defaultstate":"minecraft:dead_tube_coral_block"},"minecraft:dead_tube_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral_fan[waterlogged=true]"},"minecraft:dead_tube_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:detector_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:detector_rail[powered=false,shape=north_south]"},"minecraft:diamond_block":{"properties":{},"defaultstate":"minecraft:diamond_block"},"minecraft:diamond_ore":{"properties":{},"defaultstate":"minecraft:diamond_ore"},"minecraft:diorite":{"properties":{},"defaultstate":"minecraft:diorite"},"minecraft:diorite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:diorite_slab[type=bottom,waterlogged=false]"},"minecraft:diorite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:diorite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:diorite_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:diorite_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:dirt":{"properties":{},"defaultstate":"minecraft:dirt"},"minecraft:dispenser":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"triggered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dispenser[facing=north,triggered=false]"},"minecraft:dragon_egg":{"properties":{},"defaultstate":"minecraft:dragon_egg"},"minecraft:dragon_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:dragon_head[rotation=0]"},"minecraft:dragon_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:dragon_wall_head[facing=north]"},"minecraft:dried_kelp_block":{"properties":{},"defaultstate":"minecraft:dried_kelp_block"},"minecraft:dropper":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"triggered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dropper[facing=north,triggered=false]"},"minecraft:emerald_block":{"properties":{},"defaultstate":"minecraft:emerald_block"},"minecraft:emerald_ore":{"properties":{},"defaultstate":"minecraft:emerald_ore"},"minecraft:enchanting_table":{"properties":{},"defaultstate":"minecraft:enchanting_table"},"minecraft:end_gateway":{"properties":{},"defaultstate":"minecraft:end_gateway"},"minecraft:end_portal":{"properties":{},"defaultstate":"minecraft:end_portal"},"minecraft:end_portal_frame":{"properties":{"eye":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:end_portal_frame[eye=false,facing=north]"},"minecraft:end_rod":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:end_rod[facing=up]"},"minecraft:end_stone":{"properties":{},"defaultstate":"minecraft:end_stone"},"minecraft:end_stone_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:end_stone_brick_slab[type=bottom,waterlogged=false]"},"minecraft:end_stone_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:end_stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:end_stone_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:end_stone_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:end_stone_bricks":{"properties":{},"defaultstate":"minecraft:end_stone_bricks"},"minecraft:ender_chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:ender_chest[facing=north,waterlogged=false]"},"minecraft:farmland":{"properties":{"moisture":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:farmland[moisture=0]"},"minecraft:fern":{"properties":{},"defaultstate":"minecraft:fern"},"minecraft:fire":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire[age=0,east=false,north=false,south=false,up=false,west=false]"},"minecraft:fire_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral[waterlogged=true]"},"minecraft:fire_coral_block":{"properties":{},"defaultstate":"minecraft:fire_coral_block"},"minecraft:fire_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral_fan[waterlogged=true]"},"minecraft:fire_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:fletching_table":{"properties":{},"defaultstate":"minecraft:fletching_table"},"minecraft:flower_pot":{"properties":{},"defaultstate":"minecraft:flower_pot"},"minecraft:frosted_ice":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:frosted_ice[age=0]"},"minecraft:furnace":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:furnace[facing=north,lit=false]"},"minecraft:glass":{"properties":{},"defaultstate":"minecraft:glass"},"minecraft:glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:glowstone":{"properties":{},"defaultstate":"minecraft:glowstone"},"minecraft:gold_block":{"properties":{},"defaultstate":"minecraft:gold_block"},"minecraft:gold_ore":{"properties":{},"defaultstate":"minecraft:gold_ore"},"minecraft:granite":{"properties":{},"defaultstate":"minecraft:granite"},"minecraft:granite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:granite_slab[type=bottom,waterlogged=false]"},"minecraft:granite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:granite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:granite_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:granite_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:grass":{"properties":{},"defaultstate":"minecraft:grass"},"minecraft:grass_block":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:grass_block[snowy=false]"},"minecraft:grass_path":{"properties":{},"defaultstate":"minecraft:grass_path"},"minecraft:gravel":{"properties":{},"defaultstate":"minecraft:gravel"},"minecraft:gray_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:gray_banner[rotation=0]"},"minecraft:gray_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:gray_bed[facing=north,occupied=false,part=foot]"},"minecraft:gray_carpet":{"properties":{},"defaultstate":"minecraft:gray_carpet"},"minecraft:gray_concrete":{"properties":{},"defaultstate":"minecraft:gray_concrete"},"minecraft:gray_concrete_powder":{"properties":{},"defaultstate":"minecraft:gray_concrete_powder"},"minecraft:gray_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:gray_glazed_terracotta[facing=north]"},"minecraft:gray_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:gray_shulker_box[facing=up]"},"minecraft:gray_stained_glass":{"properties":{},"defaultstate":"minecraft:gray_stained_glass"},"minecraft:gray_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:gray_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:gray_terracotta":{"properties":{},"defaultstate":"minecraft:gray_terracotta"},"minecraft:gray_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:gray_wall_banner[facing=north]"},"minecraft:gray_wool":{"properties":{},"defaultstate":"minecraft:gray_wool"},"minecraft:green_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:green_banner[rotation=0]"},"minecraft:green_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:green_bed[facing=north,occupied=false,part=foot]"},"minecraft:green_carpet":{"properties":{},"defaultstate":"minecraft:green_carpet"},"minecraft:green_concrete":{"properties":{},"defaultstate":"minecraft:green_concrete"},"minecraft:green_concrete_powder":{"properties":{},"defaultstate":"minecraft:green_concrete_powder"},"minecraft:green_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:green_glazed_terracotta[facing=north]"},"minecraft:green_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:green_shulker_box[facing=up]"},"minecraft:green_stained_glass":{"properties":{},"defaultstate":"minecraft:green_stained_glass"},"minecraft:green_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:green_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:green_terracotta":{"properties":{},"defaultstate":"minecraft:green_terracotta"},"minecraft:green_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:green_wall_banner[facing=north]"},"minecraft:green_wool":{"properties":{},"defaultstate":"minecraft:green_wool"},"minecraft:grindstone":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:grindstone[face=wall,facing=north]"},"minecraft:hay_block":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:hay_block[axis=y]"},"minecraft:heavy_weighted_pressure_plate":{"properties":{"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:heavy_weighted_pressure_plate[power=0]"},"minecraft:hopper":{"properties":{"enabled":{"values":["true","false"],"type":"bool"},"facing":{"values":["down","north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:hopper[enabled=true,facing=down]"},"minecraft:horn_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral[waterlogged=true]"},"minecraft:horn_coral_block":{"properties":{},"defaultstate":"minecraft:horn_coral_block"},"minecraft:horn_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral_fan[waterlogged=true]"},"minecraft:horn_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:ice":{"properties":{},"defaultstate":"minecraft:ice"},"minecraft:infested_chiseled_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_chiseled_stone_bricks"},"minecraft:infested_cobblestone":{"properties":{},"defaultstate":"minecraft:infested_cobblestone"},"minecraft:infested_cracked_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_cracked_stone_bricks"},"minecraft:infested_mossy_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_mossy_stone_bricks"},"minecraft:infested_stone":{"properties":{},"defaultstate":"minecraft:infested_stone"},"minecraft:infested_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_stone_bricks"},"minecraft:iron_bars":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_bars[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:iron_block":{"properties":{},"defaultstate":"minecraft:iron_block"},"minecraft:iron_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:iron_ore":{"properties":{},"defaultstate":"minecraft:iron_ore"},"minecraft:iron_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:jack_o_lantern":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:jack_o_lantern[facing=north]"},"minecraft:jigsaw":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:jigsaw[facing=up]"},"minecraft:jukebox":{"properties":{"has_record":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jukebox[has_record=false]"},"minecraft:jungle_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_button[face=wall,facing=north,powered=false]"},"minecraft:jungle_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:jungle_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:jungle_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:jungle_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_leaves[distance=7,persistent=false]"},"minecraft:jungle_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:jungle_log[axis=y]"},"minecraft:jungle_planks":{"properties":{},"defaultstate":"minecraft:jungle_planks"},"minecraft:jungle_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_pressure_plate[powered=false]"},"minecraft:jungle_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:jungle_sapling[stage=0]"},"minecraft:jungle_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_sign[rotation=0,waterlogged=false]"},"minecraft:jungle_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_slab[type=bottom,waterlogged=false]"},"minecraft:jungle_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:jungle_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:jungle_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_wall_sign[facing=north,waterlogged=false]"},"minecraft:jungle_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:jungle_wood[axis=y]"},"minecraft:kelp":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25"],"type":"int"}},"defaultstate":"minecraft:kelp[age=0]"},"minecraft:kelp_plant":{"properties":{},"defaultstate":"minecraft:kelp_plant"},"minecraft:ladder":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:ladder[facing=north,waterlogged=false]"},"minecraft:lantern":{"properties":{"hanging":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lantern[hanging=false]"},"minecraft:lapis_block":{"properties":{},"defaultstate":"minecraft:lapis_block"},"minecraft:lapis_ore":{"properties":{},"defaultstate":"minecraft:lapis_ore"},"minecraft:large_fern":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:large_fern[half=lower]"},"minecraft:lava":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:lava[level=0]"},"minecraft:lectern":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"has_book":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lectern[facing=north,has_book=false,powered=false]"},"minecraft:lever":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lever[face=wall,facing=north,powered=false]"},"minecraft:light_blue_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_blue_banner[rotation=0]"},"minecraft:light_blue_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:light_blue_bed[facing=north,occupied=false,part=foot]"},"minecraft:light_blue_carpet":{"properties":{},"defaultstate":"minecraft:light_blue_carpet"},"minecraft:light_blue_concrete":{"properties":{},"defaultstate":"minecraft:light_blue_concrete"},"minecraft:light_blue_concrete_powder":{"properties":{},"defaultstate":"minecraft:light_blue_concrete_powder"},"minecraft:light_blue_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_blue_glazed_terracotta[facing=north]"},"minecraft:light_blue_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:light_blue_shulker_box[facing=up]"},"minecraft:light_blue_stained_glass":{"properties":{},"defaultstate":"minecraft:light_blue_stained_glass"},"minecraft:light_blue_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:light_blue_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:light_blue_terracotta":{"properties":{},"defaultstate":"minecraft:light_blue_terracotta"},"minecraft:light_blue_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_blue_wall_banner[facing=north]"},"minecraft:light_blue_wool":{"properties":{},"defaultstate":"minecraft:light_blue_wool"},"minecraft:light_gray_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_gray_banner[rotation=0]"},"minecraft:light_gray_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:light_gray_bed[facing=north,occupied=false,part=foot]"},"minecraft:light_gray_carpet":{"properties":{},"defaultstate":"minecraft:light_gray_carpet"},"minecraft:light_gray_concrete":{"properties":{},"defaultstate":"minecraft:light_gray_concrete"},"minecraft:light_gray_concrete_powder":{"properties":{},"defaultstate":"minecraft:light_gray_concrete_powder"},"minecraft:light_gray_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_gray_glazed_terracotta[facing=north]"},"minecraft:light_gray_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:light_gray_shulker_box[facing=up]"},"minecraft:light_gray_stained_glass":{"properties":{},"defaultstate":"minecraft:light_gray_stained_glass"},"minecraft:light_gray_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:light_gray_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:light_gray_terracotta":{"properties":{},"defaultstate":"minecraft:light_gray_terracotta"},"minecraft:light_gray_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_gray_wall_banner[facing=north]"},"minecraft:light_gray_wool":{"properties":{},"defaultstate":"minecraft:light_gray_wool"},"minecraft:light_weighted_pressure_plate":{"properties":{"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_weighted_pressure_plate[power=0]"},"minecraft:lilac":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:lilac[half=lower]"},"minecraft:lily_of_the_valley":{"properties":{},"defaultstate":"minecraft:lily_of_the_valley"},"minecraft:lily_pad":{"properties":{},"defaultstate":"minecraft:lily_pad"},"minecraft:lime_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:lime_banner[rotation=0]"},"minecraft:lime_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:lime_bed[facing=north,occupied=false,part=foot]"},"minecraft:lime_carpet":{"properties":{},"defaultstate":"minecraft:lime_carpet"},"minecraft:lime_concrete":{"properties":{},"defaultstate":"minecraft:lime_concrete"},"minecraft:lime_concrete_powder":{"properties":{},"defaultstate":"minecraft:lime_concrete_powder"},"minecraft:lime_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:lime_glazed_terracotta[facing=north]"},"minecraft:lime_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:lime_shulker_box[facing=up]"},"minecraft:lime_stained_glass":{"properties":{},"defaultstate":"minecraft:lime_stained_glass"},"minecraft:lime_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lime_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:lime_terracotta":{"properties":{},"defaultstate":"minecraft:lime_terracotta"},"minecraft:lime_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:lime_wall_banner[facing=north]"},"minecraft:lime_wool":{"properties":{},"defaultstate":"minecraft:lime_wool"},"minecraft:loom":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:loom[facing=north]"},"minecraft:magenta_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:magenta_banner[rotation=0]"},"minecraft:magenta_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:magenta_bed[facing=north,occupied=false,part=foot]"},"minecraft:magenta_carpet":{"properties":{},"defaultstate":"minecraft:magenta_carpet"},"minecraft:magenta_concrete":{"properties":{},"defaultstate":"minecraft:magenta_concrete"},"minecraft:magenta_concrete_powder":{"properties":{},"defaultstate":"minecraft:magenta_concrete_powder"},"minecraft:magenta_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:magenta_glazed_terracotta[facing=north]"},"minecraft:magenta_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:magenta_shulker_box[facing=up]"},"minecraft:magenta_stained_glass":{"properties":{},"defaultstate":"minecraft:magenta_stained_glass"},"minecraft:magenta_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:magenta_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:magenta_terracotta":{"properties":{},"defaultstate":"minecraft:magenta_terracotta"},"minecraft:magenta_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:magenta_wall_banner[facing=north]"},"minecraft:magenta_wool":{"properties":{},"defaultstate":"minecraft:magenta_wool"},"minecraft:magma_block":{"properties":{},"defaultstate":"minecraft:magma_block"},"minecraft:melon":{"properties":{},"defaultstate":"minecraft:melon"},"minecraft:melon_stem":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:melon_stem[age=0]"},"minecraft:mossy_cobblestone":{"properties":{},"defaultstate":"minecraft:mossy_cobblestone"},"minecraft:mossy_cobblestone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_cobblestone_slab[type=bottom,waterlogged=false]"},"minecraft:mossy_cobblestone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_cobblestone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:mossy_cobblestone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_cobblestone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:mossy_stone_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_stone_brick_slab[type=bottom,waterlogged=false]"},"minecraft:mossy_stone_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:mossy_stone_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_stone_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:mossy_stone_bricks":{"properties":{},"defaultstate":"minecraft:mossy_stone_bricks"},"minecraft:moving_piston":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"type":{"values":["normal","sticky"],"type":"enum"}},"defaultstate":"minecraft:moving_piston[facing=north,type=normal]"},"minecraft:mushroom_stem":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:mycelium":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mycelium[snowy=false]"},"minecraft:nether_brick_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:nether_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_slab[type=bottom,waterlogged=false]"},"minecraft:nether_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:nether_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:nether_bricks":{"properties":{},"defaultstate":"minecraft:nether_bricks"},"minecraft:nether_portal":{"properties":{"axis":{"values":["x","z"],"type":"enum"}},"defaultstate":"minecraft:nether_portal[axis=x]"},"minecraft:nether_quartz_ore":{"properties":{},"defaultstate":"minecraft:nether_quartz_ore"},"minecraft:nether_wart":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:nether_wart[age=0]"},"minecraft:nether_wart_block":{"properties":{},"defaultstate":"minecraft:nether_wart_block"},"minecraft:netherrack":{"properties":{},"defaultstate":"minecraft:netherrack"},"minecraft:note_block":{"properties":{"instrument":{"values":["harp","basedrum","snare","hat","bass","flute","bell","guitar","chime","xylophone","iron_xylophone","cow_bell","didgeridoo","bit","banjo","pling"],"type":"enum"},"note":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24"],"type":"int"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:note_block[instrument=harp,note=0,powered=false]"},"minecraft:oak_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_button[face=wall,facing=north,powered=false]"},"minecraft:oak_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:oak_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:oak_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:oak_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_leaves[distance=7,persistent=false]"},"minecraft:oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:oak_log[axis=y]"},"minecraft:oak_planks":{"properties":{},"defaultstate":"minecraft:oak_planks"},"minecraft:oak_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_pressure_plate[powered=false]"},"minecraft:oak_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:oak_sapling[stage=0]"},"minecraft:oak_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_sign[rotation=0,waterlogged=false]"},"minecraft:oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_slab[type=bottom,waterlogged=false]"},"minecraft:oak_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:oak_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:oak_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_wall_sign[facing=north,waterlogged=false]"},"minecraft:oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:oak_wood[axis=y]"},"minecraft:observer":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:observer[facing=south,powered=false]"},"minecraft:obsidian":{"properties":{},"defaultstate":"minecraft:obsidian"},"minecraft:orange_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:orange_banner[rotation=0]"},"minecraft:orange_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:orange_bed[facing=north,occupied=false,part=foot]"},"minecraft:orange_carpet":{"properties":{},"defaultstate":"minecraft:orange_carpet"},"minecraft:orange_concrete":{"properties":{},"defaultstate":"minecraft:orange_concrete"},"minecraft:orange_concrete_powder":{"properties":{},"defaultstate":"minecraft:orange_concrete_powder"},"minecraft:orange_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:orange_glazed_terracotta[facing=north]"},"minecraft:orange_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:orange_shulker_box[facing=up]"},"minecraft:orange_stained_glass":{"properties":{},"defaultstate":"minecraft:orange_stained_glass"},"minecraft:orange_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:orange_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:orange_terracotta":{"properties":{},"defaultstate":"minecraft:orange_terracotta"},"minecraft:orange_tulip":{"properties":{},"defaultstate":"minecraft:orange_tulip"},"minecraft:orange_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:orange_wall_banner[facing=north]"},"minecraft:orange_wool":{"properties":{},"defaultstate":"minecraft:orange_wool"},"minecraft:oxeye_daisy":{"properties":{},"defaultstate":"minecraft:oxeye_daisy"},"minecraft:packed_ice":{"properties":{},"defaultstate":"minecraft:packed_ice"},"minecraft:peony":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:peony[half=lower]"},"minecraft:petrified_oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:petrified_oak_slab[type=bottom,waterlogged=false]"},"minecraft:pink_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:pink_banner[rotation=0]"},"minecraft:pink_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:pink_bed[facing=north,occupied=false,part=foot]"},"minecraft:pink_carpet":{"properties":{},"defaultstate":"minecraft:pink_carpet"},"minecraft:pink_concrete":{"properties":{},"defaultstate":"minecraft:pink_concrete"},"minecraft:pink_concrete_powder":{"properties":{},"defaultstate":"minecraft:pink_concrete_powder"},"minecraft:pink_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:pink_glazed_terracotta[facing=north]"},"minecraft:pink_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:pink_shulker_box[facing=up]"},"minecraft:pink_stained_glass":{"properties":{},"defaultstate":"minecraft:pink_stained_glass"},"minecraft:pink_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:pink_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:pink_terracotta":{"properties":{},"defaultstate":"minecraft:pink_terracotta"},"minecraft:pink_tulip":{"properties":{},"defaultstate":"minecraft:pink_tulip"},"minecraft:pink_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:pink_wall_banner[facing=north]"},"minecraft:pink_wool":{"properties":{},"defaultstate":"minecraft:pink_wool"},"minecraft:piston":{"properties":{"extended":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:piston[extended=false,facing=north]"},"minecraft:piston_head":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"short":{"values":["true","false"],"type":"bool"},"type":{"values":["normal","sticky"],"type":"enum"}},"defaultstate":"minecraft:piston_head[facing=north,short=false,type=normal]"},"minecraft:player_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:player_head[rotation=0]"},"minecraft:player_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:player_wall_head[facing=north]"},"minecraft:podzol":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:podzol[snowy=false]"},"minecraft:polished_andesite":{"properties":{},"defaultstate":"minecraft:polished_andesite"},"minecraft:polished_andesite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_andesite_slab[type=bottom,waterlogged=false]"},"minecraft:polished_andesite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_andesite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:polished_diorite":{"properties":{},"defaultstate":"minecraft:polished_diorite"},"minecraft:polished_diorite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_diorite_slab[type=bottom,waterlogged=false]"},"minecraft:polished_diorite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_diorite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:polished_granite":{"properties":{},"defaultstate":"minecraft:polished_granite"},"minecraft:polished_granite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_granite_slab[type=bottom,waterlogged=false]"},"minecraft:polished_granite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_granite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:poppy":{"properties":{},"defaultstate":"minecraft:poppy"},"minecraft:potatoes":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:potatoes[age=0]"},"minecraft:potted_acacia_sapling":{"properties":{},"defaultstate":"minecraft:potted_acacia_sapling"},"minecraft:potted_allium":{"properties":{},"defaultstate":"minecraft:potted_allium"},"minecraft:potted_azure_bluet":{"properties":{},"defaultstate":"minecraft:potted_azure_bluet"},"minecraft:potted_bamboo":{"properties":{},"defaultstate":"minecraft:potted_bamboo"},"minecraft:potted_birch_sapling":{"properties":{},"defaultstate":"minecraft:potted_birch_sapling"},"minecraft:potted_blue_orchid":{"properties":{},"defaultstate":"minecraft:potted_blue_orchid"},"minecraft:potted_brown_mushroom":{"properties":{},"defaultstate":"minecraft:potted_brown_mushroom"},"minecraft:potted_cactus":{"properties":{},"defaultstate":"minecraft:potted_cactus"},"minecraft:potted_cornflower":{"properties":{},"defaultstate":"minecraft:potted_cornflower"},"minecraft:potted_dandelion":{"properties":{},"defaultstate":"minecraft:potted_dandelion"},"minecraft:potted_dark_oak_sapling":{"properties":{},"defaultstate":"minecraft:potted_dark_oak_sapling"},"minecraft:potted_dead_bush":{"properties":{},"defaultstate":"minecraft:potted_dead_bush"},"minecraft:potted_fern":{"properties":{},"defaultstate":"minecraft:potted_fern"},"minecraft:potted_jungle_sapling":{"properties":{},"defaultstate":"minecraft:potted_jungle_sapling"},"minecraft:potted_lily_of_the_valley":{"properties":{},"defaultstate":"minecraft:potted_lily_of_the_valley"},"minecraft:potted_oak_sapling":{"properties":{},"defaultstate":"minecraft:potted_oak_sapling"},"minecraft:potted_orange_tulip":{"properties":{},"defaultstate":"minecraft:potted_orange_tulip"},"minecraft:potted_oxeye_daisy":{"properties":{},"defaultstate":"minecraft:potted_oxeye_daisy"},"minecraft:potted_pink_tulip":{"properties":{},"defaultstate":"minecraft:potted_pink_tulip"},"minecraft:potted_poppy":{"properties":{},"defaultstate":"minecraft:potted_poppy"},"minecraft:potted_red_mushroom":{"properties":{},"defaultstate":"minecraft:potted_red_mushroom"},"minecraft:potted_red_tulip":{"properties":{},"defaultstate":"minecraft:potted_red_tulip"},"minecraft:potted_spruce_sapling":{"properties":{},"defaultstate":"minecraft:potted_spruce_sapling"},"minecraft:potted_white_tulip":{"properties":{},"defaultstate":"minecraft:potted_white_tulip"},"minecraft:potted_wither_rose":{"properties":{},"defaultstate":"minecraft:potted_wither_rose"},"minecraft:powered_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:powered_rail[powered=false,shape=north_south]"},"minecraft:prismarine":{"properties":{},"defaultstate":"minecraft:prismarine"},"minecraft:prismarine_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_brick_slab[type=bottom,waterlogged=false]"},"minecraft:prismarine_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:prismarine_bricks":{"properties":{},"defaultstate":"minecraft:prismarine_bricks"},"minecraft:prismarine_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_slab[type=bottom,waterlogged=false]"},"minecraft:prismarine_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:prismarine_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:pumpkin":{"properties":{},"defaultstate":"minecraft:pumpkin"},"minecraft:pumpkin_stem":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:pumpkin_stem[age=0]"},"minecraft:purple_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:purple_banner[rotation=0]"},"minecraft:purple_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:purple_bed[facing=north,occupied=false,part=foot]"},"minecraft:purple_carpet":{"properties":{},"defaultstate":"minecraft:purple_carpet"},"minecraft:purple_concrete":{"properties":{},"defaultstate":"minecraft:purple_concrete"},"minecraft:purple_concrete_powder":{"properties":{},"defaultstate":"minecraft:purple_concrete_powder"},"minecraft:purple_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:purple_glazed_terracotta[facing=north]"},"minecraft:purple_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:purple_shulker_box[facing=up]"},"minecraft:purple_stained_glass":{"properties":{},"defaultstate":"minecraft:purple_stained_glass"},"minecraft:purple_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purple_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:purple_terracotta":{"properties":{},"defaultstate":"minecraft:purple_terracotta"},"minecraft:purple_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:purple_wall_banner[facing=north]"},"minecraft:purple_wool":{"properties":{},"defaultstate":"minecraft:purple_wool"},"minecraft:purpur_block":{"properties":{},"defaultstate":"minecraft:purpur_block"},"minecraft:purpur_pillar":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:purpur_pillar[axis=y]"},"minecraft:purpur_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purpur_slab[type=bottom,waterlogged=false]"},"minecraft:purpur_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purpur_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:quartz_block":{"properties":{},"defaultstate":"minecraft:quartz_block"},"minecraft:quartz_pillar":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:quartz_pillar[axis=y]"},"minecraft:quartz_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:quartz_slab[type=bottom,waterlogged=false]"},"minecraft:quartz_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:quartz_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:rail":{"properties":{"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south","south_east","south_west","north_west","north_east"],"type":"enum"}},"defaultstate":"minecraft:rail[shape=north_south]"},"minecraft:red_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:red_banner[rotation=0]"},"minecraft:red_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:red_bed[facing=north,occupied=false,part=foot]"},"minecraft:red_carpet":{"properties":{},"defaultstate":"minecraft:red_carpet"},"minecraft:red_concrete":{"properties":{},"defaultstate":"minecraft:red_concrete"},"minecraft:red_concrete_powder":{"properties":{},"defaultstate":"minecraft:red_concrete_powder"},"minecraft:red_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:red_glazed_terracotta[facing=north]"},"minecraft:red_mushroom":{"properties":{},"defaultstate":"minecraft:red_mushroom"},"minecraft:red_mushroom_block":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:red_nether_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_nether_brick_slab[type=bottom,waterlogged=false]"},"minecraft:red_nether_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_nether_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:red_nether_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_nether_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:red_nether_bricks":{"properties":{},"defaultstate":"minecraft:red_nether_bricks"},"minecraft:red_sand":{"properties":{},"defaultstate":"minecraft:red_sand"},"minecraft:red_sandstone":{"properties":{},"defaultstate":"minecraft:red_sandstone"},"minecraft:red_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:red_sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:red_sandstone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:red_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:red_shulker_box[facing=up]"},"minecraft:red_stained_glass":{"properties":{},"defaultstate":"minecraft:red_stained_glass"},"minecraft:red_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:red_terracotta":{"properties":{},"defaultstate":"minecraft:red_terracotta"},"minecraft:red_tulip":{"properties":{},"defaultstate":"minecraft:red_tulip"},"minecraft:red_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:red_wall_banner[facing=north]"},"minecraft:red_wool":{"properties":{},"defaultstate":"minecraft:red_wool"},"minecraft:redstone_block":{"properties":{},"defaultstate":"minecraft:redstone_block"},"minecraft:redstone_lamp":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_lamp[lit=false]"},"minecraft:redstone_ore":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_ore[lit=false]"},"minecraft:redstone_torch":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_torch[lit=true]"},"minecraft:redstone_wall_torch":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_wall_torch[facing=north,lit=true]"},"minecraft:redstone_wire":{"properties":{"east":{"values":["up","side","none"],"type":"enum"},"north":{"values":["up","side","none"],"type":"enum"},"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"south":{"values":["up","side","none"],"type":"enum"},"west":{"values":["up","side","none"],"type":"enum"}},"defaultstate":"minecraft:redstone_wire[east=none,north=none,power=0,south=none,west=none]"},"minecraft:repeater":{"properties":{"delay":{"values":["1","2","3","4"],"type":"int"},"facing":{"values":["north","south","west","east"],"type":"direction"},"locked":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:repeater[delay=1,facing=north,locked=false,powered=false]"},"minecraft:repeating_command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:repeating_command_block[conditional=false,facing=north]"},"minecraft:rose_bush":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:rose_bush[half=lower]"},"minecraft:sand":{"properties":{},"defaultstate":"minecraft:sand"},"minecraft:sandstone":{"properties":{},"defaultstate":"minecraft:sandstone"},"minecraft:sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:sandstone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:scaffolding":{"properties":{"bottom":{"values":["true","false"],"type":"bool"},"distance":{"values":["0","1","2","3","4","5","6","7"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:scaffolding[bottom=false,distance=7,waterlogged=false]"},"minecraft:sea_lantern":{"properties":{},"defaultstate":"minecraft:sea_lantern"},"minecraft:sea_pickle":{"properties":{"pickles":{"values":["1","2","3","4"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sea_pickle[pickles=1,waterlogged=true]"},"minecraft:seagrass":{"properties":{},"defaultstate":"minecraft:seagrass"},"minecraft:shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:shulker_box[facing=up]"},"minecraft:skeleton_skull":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:skeleton_skull[rotation=0]"},"minecraft:skeleton_wall_skull":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:skeleton_wall_skull[facing=north]"},"minecraft:slime_block":{"properties":{},"defaultstate":"minecraft:slime_block"},"minecraft:smithing_table":{"properties":{},"defaultstate":"minecraft:smithing_table"},"minecraft:smoker":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smoker[facing=north,lit=false]"},"minecraft:smooth_quartz":{"properties":{},"defaultstate":"minecraft:smooth_quartz"},"minecraft:smooth_quartz_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_quartz_slab[type=bottom,waterlogged=false]"},"minecraft:smooth_quartz_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_quartz_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:smooth_red_sandstone":{"properties":{},"defaultstate":"minecraft:smooth_red_sandstone"},"minecraft:smooth_red_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_red_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:smooth_red_sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_red_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:smooth_sandstone":{"properties":{},"defaultstate":"minecraft:smooth_sandstone"},"minecraft:smooth_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:smooth_sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:smooth_stone":{"properties":{},"defaultstate":"minecraft:smooth_stone"},"minecraft:smooth_stone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_stone_slab[type=bottom,waterlogged=false]"},"minecraft:snow":{"properties":{"layers":{"values":["1","2","3","4","5","6","7","8"],"type":"int"}},"defaultstate":"minecraft:snow[layers=1]"},"minecraft:snow_block":{"properties":{},"defaultstate":"minecraft:snow_block"},"minecraft:soul_sand":{"properties":{},"defaultstate":"minecraft:soul_sand"},"minecraft:spawner":{"properties":{},"defaultstate":"minecraft:spawner"},"minecraft:sponge":{"properties":{},"defaultstate":"minecraft:sponge"},"minecraft:spruce_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_button[face=wall,facing=north,powered=false]"},"minecraft:spruce_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:spruce_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:spruce_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:spruce_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_leaves[distance=7,persistent=false]"},"minecraft:spruce_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:spruce_log[axis=y]"},"minecraft:spruce_planks":{"properties":{},"defaultstate":"minecraft:spruce_planks"},"minecraft:spruce_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_pressure_plate[powered=false]"},"minecraft:spruce_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:spruce_sapling[stage=0]"},"minecraft:spruce_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_sign[rotation=0,waterlogged=false]"},"minecraft:spruce_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_slab[type=bottom,waterlogged=false]"},"minecraft:spruce_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:spruce_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:spruce_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_wall_sign[facing=north,waterlogged=false]"},"minecraft:spruce_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:spruce_wood[axis=y]"},"minecraft:sticky_piston":{"properties":{"extended":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:sticky_piston[extended=false,facing=north]"},"minecraft:stone":{"properties":{},"defaultstate":"minecraft:stone"},"minecraft:stone_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_slab[type=bottom,waterlogged=false]"},"minecraft:stone_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:stone_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:stone_bricks":{"properties":{},"defaultstate":"minecraft:stone_bricks"},"minecraft:stone_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_button[face=wall,facing=north,powered=false]"},"minecraft:stone_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_pressure_plate[powered=false]"},"minecraft:stone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_slab[type=bottom,waterlogged=false]"},"minecraft:stone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:stonecutter":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:stonecutter[facing=north]"},"minecraft:stripped_acacia_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_acacia_log[axis=y]"},"minecraft:stripped_acacia_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_acacia_wood[axis=y]"},"minecraft:stripped_birch_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_birch_log[axis=y]"},"minecraft:stripped_birch_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_birch_wood[axis=y]"},"minecraft:stripped_dark_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_dark_oak_log[axis=y]"},"minecraft:stripped_dark_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_dark_oak_wood[axis=y]"},"minecraft:stripped_jungle_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_jungle_log[axis=y]"},"minecraft:stripped_jungle_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_jungle_wood[axis=y]"},"minecraft:stripped_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_oak_log[axis=y]"},"minecraft:stripped_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_oak_wood[axis=y]"},"minecraft:stripped_spruce_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_spruce_log[axis=y]"},"minecraft:stripped_spruce_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_spruce_wood[axis=y]"},"minecraft:structure_block":{"properties":{"mode":{"values":["save","load","corner","data"],"type":"enum"}},"defaultstate":"minecraft:structure_block[mode=save]"},"minecraft:structure_void":{"properties":{},"defaultstate":"minecraft:structure_void"},"minecraft:sugar_cane":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:sugar_cane[age=0]"},"minecraft:sunflower":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:sunflower[half=lower]"},"minecraft:sweet_berry_bush":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:sweet_berry_bush[age=0]"},"minecraft:tall_grass":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:tall_grass[half=lower]"},"minecraft:tall_seagrass":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:tall_seagrass[half=lower]"},"minecraft:terracotta":{"properties":{},"defaultstate":"minecraft:terracotta"},"minecraft:tnt":{"properties":{"unstable":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tnt[unstable=false]"},"minecraft:torch":{"properties":{},"defaultstate":"minecraft:torch"},"minecraft:trapped_chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"type":{"values":["single","left","right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:trapped_chest[facing=north,type=single,waterlogged=false]"},"minecraft:tripwire":{"properties":{"attached":{"values":["true","false"],"type":"bool"},"disarmed":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,powered=false,south=false,west=false]"},"minecraft:tripwire_hook":{"properties":{"attached":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tripwire_hook[attached=false,facing=north,powered=false]"},"minecraft:tube_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral[waterlogged=true]"},"minecraft:tube_coral_block":{"properties":{},"defaultstate":"minecraft:tube_coral_block"},"minecraft:tube_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral_fan[waterlogged=true]"},"minecraft:tube_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:turtle_egg":{"properties":{"eggs":{"values":["1","2","3","4"],"type":"int"},"hatch":{"values":["0","1","2"],"type":"int"}},"defaultstate":"minecraft:turtle_egg[eggs=1,hatch=0]"},"minecraft:vine":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:vine[east=false,north=false,south=false,up=false,west=false]"},"minecraft:void_air":{"properties":{},"defaultstate":"minecraft:void_air"},"minecraft:wall_torch":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:wall_torch[facing=north]"},"minecraft:water":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:water[level=0]"},"minecraft:wet_sponge":{"properties":{},"defaultstate":"minecraft:wet_sponge"},"minecraft:wheat":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:wheat[age=0]"},"minecraft:white_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:white_banner[rotation=0]"},"minecraft:white_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:white_bed[facing=north,occupied=false,part=foot]"},"minecraft:white_carpet":{"properties":{},"defaultstate":"minecraft:white_carpet"},"minecraft:white_concrete":{"properties":{},"defaultstate":"minecraft:white_concrete"},"minecraft:white_concrete_powder":{"properties":{},"defaultstate":"minecraft:white_concrete_powder"},"minecraft:white_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:white_glazed_terracotta[facing=north]"},"minecraft:white_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:white_shulker_box[facing=up]"},"minecraft:white_stained_glass":{"properties":{},"defaultstate":"minecraft:white_stained_glass"},"minecraft:white_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:white_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:white_terracotta":{"properties":{},"defaultstate":"minecraft:white_terracotta"},"minecraft:white_tulip":{"properties":{},"defaultstate":"minecraft:white_tulip"},"minecraft:white_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:white_wall_banner[facing=north]"},"minecraft:white_wool":{"properties":{},"defaultstate":"minecraft:white_wool"},"minecraft:wither_rose":{"properties":{},"defaultstate":"minecraft:wither_rose"},"minecraft:wither_skeleton_skull":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:wither_skeleton_skull[rotation=0]"},"minecraft:wither_skeleton_wall_skull":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:wither_skeleton_wall_skull[facing=north]"},"minecraft:yellow_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:yellow_banner[rotation=0]"},"minecraft:yellow_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:yellow_bed[facing=north,occupied=false,part=foot]"},"minecraft:yellow_carpet":{"properties":{},"defaultstate":"minecraft:yellow_carpet"},"minecraft:yellow_concrete":{"properties":{},"defaultstate":"minecraft:yellow_concrete"},"minecraft:yellow_concrete_powder":{"properties":{},"defaultstate":"minecraft:yellow_concrete_powder"},"minecraft:yellow_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:yellow_glazed_terracotta[facing=north]"},"minecraft:yellow_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:yellow_shulker_box[facing=up]"},"minecraft:yellow_stained_glass":{"properties":{},"defaultstate":"minecraft:yellow_stained_glass"},"minecraft:yellow_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:yellow_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:yellow_terracotta":{"properties":{},"defaultstate":"minecraft:yellow_terracotta"},"minecraft:yellow_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:yellow_wall_banner[facing=north]"},"minecraft:yellow_wool":{"properties":{},"defaultstate":"minecraft:yellow_wool"},"minecraft:zombie_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:zombie_head[rotation=0]"},"minecraft:zombie_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:zombie_wall_head[facing=north]"}},"items":["minecraft:acacia_boat","minecraft:acacia_button","minecraft:acacia_door","minecraft:acacia_fence","minecraft:acacia_fence_gate","minecraft:acacia_leaves","minecraft:acacia_log","minecraft:acacia_planks","minecraft:acacia_pressure_plate","minecraft:acacia_sapling","minecraft:acacia_sign","minecraft:acacia_slab","minecraft:acacia_stairs","minecraft:acacia_trapdoor","minecraft:acacia_wood","minecraft:activator_rail","minecraft:air","minecraft:allium","minecraft:andesite","minecraft:andesite_slab","minecraft:andesite_stairs","minecraft:andesite_wall","minecraft:anvil","minecraft:apple","minecraft:armor_stand","minecraft:arrow","minecraft:azure_bluet","minecraft:baked_potato","minecraft:bamboo","minecraft:barrel","minecraft:barrier","minecraft:bat_spawn_egg","minecraft:beacon","minecraft:bedrock","minecraft:beef","minecraft:beetroot","minecraft:beetroot_seeds","minecraft:beetroot_soup","minecraft:bell","minecraft:birch_boat","minecraft:birch_button","minecraft:birch_door","minecraft:birch_fence","minecraft:birch_fence_gate","minecraft:birch_leaves","minecraft:birch_log","minecraft:birch_planks","minecraft:birch_pressure_plate","minecraft:birch_sapling","minecraft:birch_sign","minecraft:birch_slab","minecraft:birch_stairs","minecraft:birch_trapdoor","minecraft:birch_wood","minecraft:black_banner","minecraft:black_bed","minecraft:black_carpet","minecraft:black_concrete","minecraft:black_concrete_powder","minecraft:black_dye","minecraft:black_glazed_terracotta","minecraft:black_shulker_box","minecraft:black_stained_glass","minecraft:black_stained_glass_pane","minecraft:black_terracotta","minecraft:black_wool","minecraft:blast_furnace","minecraft:blaze_powder","minecraft:blaze_rod","minecraft:blaze_spawn_egg","minecraft:blue_banner","minecraft:blue_bed","minecraft:blue_carpet","minecraft:blue_concrete","minecraft:blue_concrete_powder","minecraft:blue_dye","minecraft:blue_glazed_terracotta","minecraft:blue_ice","minecraft:blue_orchid","minecraft:blue_shulker_box","minecraft:blue_stained_glass","minecraft:blue_stained_glass_pane","minecraft:blue_terracotta","minecraft:blue_wool","minecraft:bone","minecraft:bone_block","minecraft:bone_meal","minecraft:book","minecraft:bookshelf","minecraft:bow","minecraft:bowl","minecraft:brain_coral","minecraft:brain_coral_block","minecraft:brain_coral_fan","minecraft:bread","minecraft:brewing_stand","minecraft:brick","minecraft:brick_slab","minecraft:brick_stairs","minecraft:brick_wall","minecraft:bricks","minecraft:brown_banner","minecraft:brown_bed","minecraft:brown_carpet","minecraft:brown_concrete","minecraft:brown_concrete_powder","minecraft:brown_dye","minecraft:brown_glazed_terracotta","minecraft:brown_mushroom","minecraft:brown_mushroom_block","minecraft:brown_shulker_box","minecraft:brown_stained_glass","minecraft:brown_stained_glass_pane","minecraft:brown_terracotta","minecraft:brown_wool","minecraft:bubble_coral","minecraft:bubble_coral_block","minecraft:bubble_coral_fan","minecraft:bucket","minecraft:cactus","minecraft:cake","minecraft:campfire","minecraft:carrot","minecraft:carrot_on_a_stick","minecraft:cartography_table","minecraft:carved_pumpkin","minecraft:cat_spawn_egg","minecraft:cauldron","minecraft:cave_spider_spawn_egg","minecraft:chain_command_block","minecraft:chainmail_boots","minecraft:chainmail_chestplate","minecraft:chainmail_helmet","minecraft:chainmail_leggings","minecraft:charcoal","minecraft:chest","minecraft:chest_minecart","minecraft:chicken","minecraft:chicken_spawn_egg","minecraft:chipped_anvil","minecraft:chiseled_quartz_block","minecraft:chiseled_red_sandstone","minecraft:chiseled_sandstone","minecraft:chiseled_stone_bricks","minecraft:chorus_flower","minecraft:chorus_fruit","minecraft:chorus_plant","minecraft:clay","minecraft:clay_ball","minecraft:clock","minecraft:coal","minecraft:coal_block","minecraft:coal_ore","minecraft:coarse_dirt","minecraft:cobblestone","minecraft:cobblestone_slab","minecraft:cobblestone_stairs","minecraft:cobblestone_wall","minecraft:cobweb","minecraft:cocoa_beans","minecraft:cod","minecraft:cod_bucket","minecraft:cod_spawn_egg","minecraft:command_block","minecraft:command_block_minecart","minecraft:comparator","minecraft:compass","minecraft:composter","minecraft:conduit","minecraft:cooked_beef","minecraft:cooked_chicken","minecraft:cooked_cod","minecraft:cooked_mutton","minecraft:cooked_porkchop","minecraft:cooked_rabbit","minecraft:cooked_salmon","minecraft:cookie","minecraft:cornflower","minecraft:cow_spawn_egg","minecraft:cracked_stone_bricks","minecraft:crafting_table","minecraft:creeper_banner_pattern","minecraft:creeper_head","minecraft:creeper_spawn_egg","minecraft:crossbow","minecraft:cut_red_sandstone","minecraft:cut_red_sandstone_slab","minecraft:cut_sandstone","minecraft:cut_sandstone_slab","minecraft:cyan_banner","minecraft:cyan_bed","minecraft:cyan_carpet","minecraft:cyan_concrete","minecraft:cyan_concrete_powder","minecraft:cyan_dye","minecraft:cyan_glazed_terracotta","minecraft:cyan_shulker_box","minecraft:cyan_stained_glass","minecraft:cyan_stained_glass_pane","minecraft:cyan_terracotta","minecraft:cyan_wool","minecraft:damaged_anvil","minecraft:dandelion","minecraft:dark_oak_boat","minecraft:dark_oak_button","minecraft:dark_oak_door","minecraft:dark_oak_fence","minecraft:dark_oak_fence_gate","minecraft:dark_oak_leaves","minecraft:dark_oak_log","minecraft:dark_oak_planks","minecraft:dark_oak_pressure_plate","minecraft:dark_oak_sapling","minecraft:dark_oak_sign","minecraft:dark_oak_slab","minecraft:dark_oak_stairs","minecraft:dark_oak_trapdoor","minecraft:dark_oak_wood","minecraft:dark_prismarine","minecraft:dark_prismarine_slab","minecraft:dark_prismarine_stairs","minecraft:daylight_detector","minecraft:dead_brain_coral","minecraft:dead_brain_coral_block","minecraft:dead_brain_coral_fan","minecraft:dead_bubble_coral","minecraft:dead_bubble_coral_block","minecraft:dead_bubble_coral_fan","minecraft:dead_bush","minecraft:dead_fire_coral","minecraft:dead_fire_coral_block","minecraft:dead_fire_coral_fan","minecraft:dead_horn_coral","minecraft:dead_horn_coral_block","minecraft:dead_horn_coral_fan","minecraft:dead_tube_coral","minecraft:dead_tube_coral_block","minecraft:dead_tube_coral_fan","minecraft:debug_stick","minecraft:detector_rail","minecraft:diamond","minecraft:diamond_axe","minecraft:diamond_block","minecraft:diamond_boots","minecraft:diamond_chestplate","minecraft:diamond_helmet","minecraft:diamond_hoe","minecraft:diamond_horse_armor","minecraft:diamond_leggings","minecraft:diamond_ore","minecraft:diamond_pickaxe","minecraft:diamond_shovel","minecraft:diamond_sword","minecraft:diorite","minecraft:diorite_slab","minecraft:diorite_stairs","minecraft:diorite_wall","minecraft:dirt","minecraft:dispenser","minecraft:dolphin_spawn_egg","minecraft:donkey_spawn_egg","minecraft:dragon_breath","minecraft:dragon_egg","minecraft:dragon_head","minecraft:dried_kelp","minecraft:dried_kelp_block","minecraft:dropper","minecraft:drowned_spawn_egg","minecraft:egg","minecraft:elder_guardian_spawn_egg","minecraft:elytra","minecraft:emerald","minecraft:emerald_block","minecraft:emerald_ore","minecraft:enchanted_book","minecraft:enchanted_golden_apple","minecraft:enchanting_table","minecraft:end_crystal","minecraft:end_portal_frame","minecraft:end_rod","minecraft:end_stone","minecraft:end_stone_brick_slab","minecraft:end_stone_brick_stairs","minecraft:end_stone_brick_wall","minecraft:end_stone_bricks","minecraft:ender_chest","minecraft:ender_eye","minecraft:ender_pearl","minecraft:enderman_spawn_egg","minecraft:endermite_spawn_egg","minecraft:evoker_spawn_egg","minecraft:experience_bottle","minecraft:farmland","minecraft:feather","minecraft:fermented_spider_eye","minecraft:fern","minecraft:filled_map","minecraft:fire_charge","minecraft:fire_coral","minecraft:fire_coral_block","minecraft:fire_coral_fan","minecraft:firework_rocket","minecraft:firework_star","minecraft:fishing_rod","minecraft:fletching_table","minecraft:flint","minecraft:flint_and_steel","minecraft:flower_banner_pattern","minecraft:flower_pot","minecraft:fox_spawn_egg","minecraft:furnace","minecraft:furnace_minecart","minecraft:ghast_spawn_egg","minecraft:ghast_tear","minecraft:glass","minecraft:glass_bottle","minecraft:glass_pane","minecraft:glistering_melon_slice","minecraft:globe_banner_pattern","minecraft:glowstone","minecraft:glowstone_dust","minecraft:gold_block","minecraft:gold_ingot","minecraft:gold_nugget","minecraft:gold_ore","minecraft:golden_apple","minecraft:golden_axe","minecraft:golden_boots","minecraft:golden_carrot","minecraft:golden_chestplate","minecraft:golden_helmet","minecraft:golden_hoe","minecraft:golden_horse_armor","minecraft:golden_leggings","minecraft:golden_pickaxe","minecraft:golden_shovel","minecraft:golden_sword","minecraft:granite","minecraft:granite_slab","minecraft:granite_stairs","minecraft:granite_wall","minecraft:grass","minecraft:grass_block","minecraft:grass_path","minecraft:gravel","minecraft:gray_banner","minecraft:gray_bed","minecraft:gray_carpet","minecraft:gray_concrete","minecraft:gray_concrete_powder","minecraft:gray_dye","minecraft:gray_glazed_terracotta","minecraft:gray_shulker_box","minecraft:gray_stained_glass","minecraft:gray_stained_glass_pane","minecraft:gray_terracotta","minecraft:gray_wool","minecraft:green_banner","minecraft:green_bed","minecraft:green_carpet","minecraft:green_concrete","minecraft:green_concrete_powder","minecraft:green_dye","minecraft:green_glazed_terracotta","minecraft:green_shulker_box","minecraft:green_stained_glass","minecraft:green_stained_glass_pane","minecraft:green_terracotta","minecraft:green_wool","minecraft:grindstone","minecraft:guardian_spawn_egg","minecraft:gunpowder","minecraft:hay_block","minecraft:heart_of_the_sea","minecraft:heavy_weighted_pressure_plate","minecraft:hopper","minecraft:hopper_minecart","minecraft:horn_coral","minecraft:horn_coral_block","minecraft:horn_coral_fan","minecraft:horse_spawn_egg","minecraft:husk_spawn_egg","minecraft:ice","minecraft:infested_chiseled_stone_bricks","minecraft:infested_cobblestone","minecraft:infested_cracked_stone_bricks","minecraft:infested_mossy_stone_bricks","minecraft:infested_stone","minecraft:infested_stone_bricks","minecraft:ink_sac","minecraft:iron_axe","minecraft:iron_bars","minecraft:iron_block","minecraft:iron_boots","minecraft:iron_chestplate","minecraft:iron_door","minecraft:iron_helmet","minecraft:iron_hoe","minecraft:iron_horse_armor","minecraft:iron_ingot","minecraft:iron_leggings","minecraft:iron_nugget","minecraft:iron_ore","minecraft:iron_pickaxe","minecraft:iron_shovel","minecraft:iron_sword","minecraft:iron_trapdoor","minecraft:item_frame","minecraft:jack_o_lantern","minecraft:jigsaw","minecraft:jukebox","minecraft:jungle_boat","minecraft:jungle_button","minecraft:jungle_door","minecraft:jungle_fence","minecraft:jungle_fence_gate","minecraft:jungle_leaves","minecraft:jungle_log","minecraft:jungle_planks","minecraft:jungle_pressure_plate","minecraft:jungle_sapling","minecraft:jungle_sign","minecraft:jungle_slab","minecraft:jungle_stairs","minecraft:jungle_trapdoor","minecraft:jungle_wood","minecraft:kelp","minecraft:knowledge_book","minecraft:ladder","minecraft:lantern","minecraft:lapis_block","minecraft:lapis_lazuli","minecraft:lapis_ore","minecraft:large_fern","minecraft:lava_bucket","minecraft:lead","minecraft:leather","minecraft:leather_boots","minecraft:leather_chestplate","minecraft:leather_helmet","minecraft:leather_horse_armor","minecraft:leather_leggings","minecraft:lectern","minecraft:lever","minecraft:light_blue_banner","minecraft:light_blue_bed","minecraft:light_blue_carpet","minecraft:light_blue_concrete","minecraft:light_blue_concrete_powder","minecraft:light_blue_dye","minecraft:light_blue_glazed_terracotta","minecraft:light_blue_shulker_box","minecraft:light_blue_stained_glass","minecraft:light_blue_stained_glass_pane","minecraft:light_blue_terracotta","minecraft:light_blue_wool","minecraft:light_gray_banner","minecraft:light_gray_bed","minecraft:light_gray_carpet","minecraft:light_gray_concrete","minecraft:light_gray_concrete_powder","minecraft:light_gray_dye","minecraft:light_gray_glazed_terracotta","minecraft:light_gray_shulker_box","minecraft:light_gray_stained_glass","minecraft:light_gray_stained_glass_pane","minecraft:light_gray_terracotta","minecraft:light_gray_wool","minecraft:light_weighted_pressure_plate","minecraft:lilac","minecraft:lily_of_the_valley","minecraft:lily_pad","minecraft:lime_banner","minecraft:lime_bed","minecraft:lime_carpet","minecraft:lime_concrete","minecraft:lime_concrete_powder","minecraft:lime_dye","minecraft:lime_glazed_terracotta","minecraft:lime_shulker_box","minecraft:lime_stained_glass","minecraft:lime_stained_glass_pane","minecraft:lime_terracotta","minecraft:lime_wool","minecraft:lingering_potion","minecraft:llama_spawn_egg","minecraft:loom","minecraft:magenta_banner","minecraft:magenta_bed","minecraft:magenta_carpet","minecraft:magenta_concrete","minecraft:magenta_concrete_powder","minecraft:magenta_dye","minecraft:magenta_glazed_terracotta","minecraft:magenta_shulker_box","minecraft:magenta_stained_glass","minecraft:magenta_stained_glass_pane","minecraft:magenta_terracotta","minecraft:magenta_wool","minecraft:magma_block","minecraft:magma_cream","minecraft:magma_cube_spawn_egg","minecraft:map","minecraft:melon","minecraft:melon_seeds","minecraft:melon_slice","minecraft:milk_bucket","minecraft:minecart","minecraft:mojang_banner_pattern","minecraft:mooshroom_spawn_egg","minecraft:mossy_cobblestone","minecraft:mossy_cobblestone_slab","minecraft:mossy_cobblestone_stairs","minecraft:mossy_cobblestone_wall","minecraft:mossy_stone_brick_slab","minecraft:mossy_stone_brick_stairs","minecraft:mossy_stone_brick_wall","minecraft:mossy_stone_bricks","minecraft:mule_spawn_egg","minecraft:mushroom_stem","minecraft:mushroom_stew","minecraft:music_disc_11","minecraft:music_disc_13","minecraft:music_disc_blocks","minecraft:music_disc_cat","minecraft:music_disc_chirp","minecraft:music_disc_far","minecraft:music_disc_mall","minecraft:music_disc_mellohi","minecraft:music_disc_stal","minecraft:music_disc_strad","minecraft:music_disc_wait","minecraft:music_disc_ward","minecraft:mutton","minecraft:mycelium","minecraft:name_tag","minecraft:nautilus_shell","minecraft:nether_brick","minecraft:nether_brick_fence","minecraft:nether_brick_slab","minecraft:nether_brick_stairs","minecraft:nether_brick_wall","minecraft:nether_bricks","minecraft:nether_quartz_ore","minecraft:nether_star","minecraft:nether_wart","minecraft:nether_wart_block","minecraft:netherrack","minecraft:note_block","minecraft:oak_boat","minecraft:oak_button","minecraft:oak_door","minecraft:oak_fence","minecraft:oak_fence_gate","minecraft:oak_leaves","minecraft:oak_log","minecraft:oak_planks","minecraft:oak_pressure_plate","minecraft:oak_sapling","minecraft:oak_sign","minecraft:oak_slab","minecraft:oak_stairs","minecraft:oak_trapdoor","minecraft:oak_wood","minecraft:observer","minecraft:obsidian","minecraft:ocelot_spawn_egg","minecraft:orange_banner","minecraft:orange_bed","minecraft:orange_carpet","minecraft:orange_concrete","minecraft:orange_concrete_powder","minecraft:orange_dye","minecraft:orange_glazed_terracotta","minecraft:orange_shulker_box","minecraft:orange_stained_glass","minecraft:orange_stained_glass_pane","minecraft:orange_terracotta","minecraft:orange_tulip","minecraft:orange_wool","minecraft:oxeye_daisy","minecraft:packed_ice","minecraft:painting","minecraft:panda_spawn_egg","minecraft:paper","minecraft:parrot_spawn_egg","minecraft:peony","minecraft:petrified_oak_slab","minecraft:phantom_membrane","minecraft:phantom_spawn_egg","minecraft:pig_spawn_egg","minecraft:pillager_spawn_egg","minecraft:pink_banner","minecraft:pink_bed","minecraft:pink_carpet","minecraft:pink_concrete","minecraft:pink_concrete_powder","minecraft:pink_dye","minecraft:pink_glazed_terracotta","minecraft:pink_shulker_box","minecraft:pink_stained_glass","minecraft:pink_stained_glass_pane","minecraft:pink_terracotta","minecraft:pink_tulip","minecraft:pink_wool","minecraft:piston","minecraft:player_head","minecraft:podzol","minecraft:poisonous_potato","minecraft:polar_bear_spawn_egg","minecraft:polished_andesite","minecraft:polished_andesite_slab","minecraft:polished_andesite_stairs","minecraft:polished_diorite","minecraft:polished_diorite_slab","minecraft:polished_diorite_stairs","minecraft:polished_granite","minecraft:polished_granite_slab","minecraft:polished_granite_stairs","minecraft:popped_chorus_fruit","minecraft:poppy","minecraft:porkchop","minecraft:potato","minecraft:potion","minecraft:powered_rail","minecraft:prismarine","minecraft:prismarine_brick_slab","minecraft:prismarine_brick_stairs","minecraft:prismarine_bricks","minecraft:prismarine_crystals","minecraft:prismarine_shard","minecraft:prismarine_slab","minecraft:prismarine_stairs","minecraft:prismarine_wall","minecraft:pufferfish","minecraft:pufferfish_bucket","minecraft:pufferfish_spawn_egg","minecraft:pumpkin","minecraft:pumpkin_pie","minecraft:pumpkin_seeds","minecraft:purple_banner","minecraft:purple_bed","minecraft:purple_carpet","minecraft:purple_concrete","minecraft:purple_concrete_powder","minecraft:purple_dye","minecraft:purple_glazed_terracotta","minecraft:purple_shulker_box","minecraft:purple_stained_glass","minecraft:purple_stained_glass_pane","minecraft:purple_terracotta","minecraft:purple_wool","minecraft:purpur_block","minecraft:purpur_pillar","minecraft:purpur_slab","minecraft:purpur_stairs","minecraft:quartz","minecraft:quartz_block","minecraft:quartz_pillar","minecraft:quartz_slab","minecraft:quartz_stairs","minecraft:rabbit","minecraft:rabbit_foot","minecraft:rabbit_hide","minecraft:rabbit_spawn_egg","minecraft:rabbit_stew","minecraft:rail","minecraft:ravager_spawn_egg","minecraft:red_banner","minecraft:red_bed","minecraft:red_carpet","minecraft:red_concrete","minecraft:red_concrete_powder","minecraft:red_dye","minecraft:red_glazed_terracotta","minecraft:red_mushroom","minecraft:red_mushroom_block","minecraft:red_nether_brick_slab","minecraft:red_nether_brick_stairs","minecraft:red_nether_brick_wall","minecraft:red_nether_bricks","minecraft:red_sand","minecraft:red_sandstone","minecraft:red_sandstone_slab","minecraft:red_sandstone_stairs","minecraft:red_sandstone_wall","minecraft:red_shulker_box","minecraft:red_stained_glass","minecraft:red_stained_glass_pane","minecraft:red_terracotta","minecraft:red_tulip","minecraft:red_wool","minecraft:redstone","minecraft:redstone_block","minecraft:redstone_lamp","minecraft:redstone_ore","minecraft:redstone_torch","minecraft:repeater","minecraft:repeating_command_block","minecraft:rose_bush","minecraft:rotten_flesh","minecraft:saddle","minecraft:salmon","minecraft:salmon_bucket","minecraft:salmon_spawn_egg","minecraft:sand","minecraft:sandstone","minecraft:sandstone_slab","minecraft:sandstone_stairs","minecraft:sandstone_wall","minecraft:scaffolding","minecraft:scute","minecraft:sea_lantern","minecraft:sea_pickle","minecraft:seagrass","minecraft:shears","minecraft:sheep_spawn_egg","minecraft:shield","minecraft:shulker_box","minecraft:shulker_shell","minecraft:shulker_spawn_egg","minecraft:silverfish_spawn_egg","minecraft:skeleton_horse_spawn_egg","minecraft:skeleton_skull","minecraft:skeleton_spawn_egg","minecraft:skull_banner_pattern","minecraft:slime_ball","minecraft:slime_block","minecraft:slime_spawn_egg","minecraft:smithing_table","minecraft:smoker","minecraft:smooth_quartz","minecraft:smooth_quartz_slab","minecraft:smooth_quartz_stairs","minecraft:smooth_red_sandstone","minecraft:smooth_red_sandstone_slab","minecraft:smooth_red_sandstone_stairs","minecraft:smooth_sandstone","minecraft:smooth_sandstone_slab","minecraft:smooth_sandstone_stairs","minecraft:smooth_stone","minecraft:smooth_stone_slab","minecraft:snow","minecraft:snow_block","minecraft:snowball","minecraft:soul_sand","minecraft:spawner","minecraft:spectral_arrow","minecraft:spider_eye","minecraft:spider_spawn_egg","minecraft:splash_potion","minecraft:sponge","minecraft:spruce_boat","minecraft:spruce_button","minecraft:spruce_door","minecraft:spruce_fence","minecraft:spruce_fence_gate","minecraft:spruce_leaves","minecraft:spruce_log","minecraft:spruce_planks","minecraft:spruce_pressure_plate","minecraft:spruce_sapling","minecraft:spruce_sign","minecraft:spruce_slab","minecraft:spruce_stairs","minecraft:spruce_trapdoor","minecraft:spruce_wood","minecraft:squid_spawn_egg","minecraft:stick","minecraft:sticky_piston","minecraft:stone","minecraft:stone_axe","minecraft:stone_brick_slab","minecraft:stone_brick_stairs","minecraft:stone_brick_wall","minecraft:stone_bricks","minecraft:stone_button","minecraft:stone_hoe","minecraft:stone_pickaxe","minecraft:stone_pressure_plate","minecraft:stone_shovel","minecraft:stone_slab","minecraft:stone_stairs","minecraft:stone_sword","minecraft:stonecutter","minecraft:stray_spawn_egg","minecraft:string","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood","minecraft:structure_block","minecraft:structure_void","minecraft:sugar","minecraft:sugar_cane","minecraft:sunflower","minecraft:suspicious_stew","minecraft:sweet_berries","minecraft:tall_grass","minecraft:terracotta","minecraft:tipped_arrow","minecraft:tnt","minecraft:tnt_minecart","minecraft:torch","minecraft:totem_of_undying","minecraft:trader_llama_spawn_egg","minecraft:trapped_chest","minecraft:trident","minecraft:tripwire_hook","minecraft:tropical_fish","minecraft:tropical_fish_bucket","minecraft:tropical_fish_spawn_egg","minecraft:tube_coral","minecraft:tube_coral_block","minecraft:tube_coral_fan","minecraft:turtle_egg","minecraft:turtle_helmet","minecraft:turtle_spawn_egg","minecraft:vex_spawn_egg","minecraft:villager_spawn_egg","minecraft:vindicator_spawn_egg","minecraft:vine","minecraft:wandering_trader_spawn_egg","minecraft:water_bucket","minecraft:wet_sponge","minecraft:wheat","minecraft:wheat_seeds","minecraft:white_banner","minecraft:white_bed","minecraft:white_carpet","minecraft:white_concrete","minecraft:white_concrete_powder","minecraft:white_dye","minecraft:white_glazed_terracotta","minecraft:white_shulker_box","minecraft:white_stained_glass","minecraft:white_stained_glass_pane","minecraft:white_terracotta","minecraft:white_tulip","minecraft:white_wool","minecraft:witch_spawn_egg","minecraft:wither_rose","minecraft:wither_skeleton_skull","minecraft:wither_skeleton_spawn_egg","minecraft:wolf_spawn_egg","minecraft:wooden_axe","minecraft:wooden_hoe","minecraft:wooden_pickaxe","minecraft:wooden_shovel","minecraft:wooden_sword","minecraft:writable_book","minecraft:written_book","minecraft:yellow_banner","minecraft:yellow_bed","minecraft:yellow_carpet","minecraft:yellow_concrete","minecraft:yellow_concrete_powder","minecraft:yellow_dye","minecraft:yellow_glazed_terracotta","minecraft:yellow_shulker_box","minecraft:yellow_stained_glass","minecraft:yellow_stained_glass_pane","minecraft:yellow_terracotta","minecraft:yellow_wool","minecraft:zombie_head","minecraft:zombie_horse_spawn_egg","minecraft:zombie_pigman_spawn_egg","minecraft:zombie_spawn_egg","minecraft:zombie_villager_spawn_egg"],"entities":["minecraft:area_effect_cloud","minecraft:armor_stand","minecraft:arrow","minecraft:bat","minecraft:blaze","minecraft:boat","minecraft:cat","minecraft:cave_spider","minecraft:chest_minecart","minecraft:chicken","minecraft:cod","minecraft:command_block_minecart","minecraft:cow","minecraft:creeper","minecraft:dolphin","minecraft:donkey","minecraft:dragon_fireball","minecraft:drowned","minecraft:egg","minecraft:elder_guardian","minecraft:end_crystal","minecraft:ender_dragon","minecraft:ender_pearl","minecraft:enderman","minecraft:endermite","minecraft:evoker","minecraft:evoker_fangs","minecraft:experience_bottle","minecraft:experience_orb","minecraft:eye_of_ender","minecraft:falling_block","minecraft:fireball","minecraft:firework_rocket","minecraft:fishing_bobber","minecraft:fox","minecraft:furnace_minecart","minecraft:ghast","minecraft:giant","minecraft:guardian","minecraft:hopper_minecart","minecraft:horse","minecraft:husk","minecraft:illusioner","minecraft:iron_golem","minecraft:item","minecraft:item_frame","minecraft:leash_knot","minecraft:lightning_bolt","minecraft:llama","minecraft:llama_spit","minecraft:magma_cube","minecraft:minecart","minecraft:mooshroom","minecraft:mule","minecraft:ocelot","minecraft:painting","minecraft:panda","minecraft:parrot","minecraft:phantom","minecraft:pig","minecraft:pillager","minecraft:player","minecraft:polar_bear","minecraft:potion","minecraft:pufferfish","minecraft:rabbit","minecraft:ravager","minecraft:salmon","minecraft:sheep","minecraft:shulker","minecraft:shulker_bullet","minecraft:silverfish","minecraft:skeleton","minecraft:skeleton_horse","minecraft:slime","minecraft:small_fireball","minecraft:snow_golem","minecraft:snowball","minecraft:spawner_minecart","minecraft:spectral_arrow","minecraft:spider","minecraft:squid","minecraft:stray","minecraft:tnt","minecraft:tnt_minecart","minecraft:trader_llama","minecraft:trident","minecraft:tropical_fish","minecraft:turtle","minecraft:vex","minecraft:villager","minecraft:vindicator","minecraft:wandering_trader","minecraft:witch","minecraft:wither","minecraft:wither_skeleton","minecraft:wither_skull","minecraft:wolf","minecraft:zombie","minecraft:zombie_horse","minecraft:zombie_pigman","minecraft:zombie_villager"],"biomes":["minecraft:badlands","minecraft:badlands_plateau","minecraft:bamboo_jungle","minecraft:bamboo_jungle_hills","minecraft:beach","minecraft:birch_forest","minecraft:birch_forest_hills","minecraft:cold_ocean","minecraft:dark_forest","minecraft:dark_forest_hills","minecraft:deep_cold_ocean","minecraft:deep_frozen_ocean","minecraft:deep_lukewarm_ocean","minecraft:deep_ocean","minecraft:deep_warm_ocean","minecraft:desert","minecraft:desert_hills","minecraft:desert_lakes","minecraft:end_barrens","minecraft:end_highlands","minecraft:end_midlands","minecraft:eroded_badlands","minecraft:flower_forest","minecraft:forest","minecraft:frozen_ocean","minecraft:frozen_river","minecraft:giant_spruce_taiga","minecraft:giant_spruce_taiga_hills","minecraft:giant_tree_taiga","minecraft:giant_tree_taiga_hills","minecraft:gravelly_mountains","minecraft:ice_spikes","minecraft:jungle","minecraft:jungle_edge","minecraft:jungle_hills","minecraft:lukewarm_ocean","minecraft:modified_badlands_plateau","minecraft:modified_gravelly_mountains","minecraft:modified_jungle","minecraft:modified_jungle_edge","minecraft:modified_wooded_badlands_plateau","minecraft:mountain_edge","minecraft:mountains","minecraft:mushroom_field_shore","minecraft:mushroom_fields","minecraft:nether","minecraft:ocean","minecraft:plains","minecraft:river","minecraft:savanna","minecraft:savanna_plateau","minecraft:shattered_savanna","minecraft:shattered_savanna_plateau","minecraft:small_end_islands","minecraft:snowy_beach","minecraft:snowy_mountains","minecraft:snowy_taiga","minecraft:snowy_taiga_hills","minecraft:snowy_taiga_mountains","minecraft:snowy_tundra","minecraft:stone_shore","minecraft:sunflower_plains","minecraft:swamp","minecraft:swamp_hills","minecraft:taiga","minecraft:taiga_hills","minecraft:taiga_mountains","minecraft:tall_birch_forest","minecraft:tall_birch_hills","minecraft:the_end","minecraft:the_void","minecraft:warm_ocean","minecraft:wooded_badlands_plateau","minecraft:wooded_hills","minecraft:wooded_mountains"],"blocktags":{"minecraft:slabs":["minecraft:stone_slab","minecraft:smooth_stone_slab","minecraft:stone_brick_slab","minecraft:sandstone_slab","minecraft:acacia_slab","minecraft:birch_slab","minecraft:dark_oak_slab","minecraft:jungle_slab","minecraft:oak_slab","minecraft:spruce_slab","minecraft:purpur_slab","minecraft:quartz_slab","minecraft:red_sandstone_slab","minecraft:brick_slab","minecraft:cobblestone_slab","minecraft:nether_brick_slab","minecraft:petrified_oak_slab","minecraft:prismarine_slab","minecraft:prismarine_brick_slab","minecraft:dark_prismarine_slab","minecraft:polished_granite_slab","minecraft:smooth_red_sandstone_slab","minecraft:mossy_stone_brick_slab","minecraft:polished_diorite_slab","minecraft:mossy_cobblestone_slab","minecraft:end_stone_brick_slab","minecraft:smooth_sandstone_slab","minecraft:smooth_quartz_slab","minecraft:granite_slab","minecraft:andesite_slab","minecraft:red_nether_brick_slab","minecraft:polished_andesite_slab","minecraft:diorite_slab","minecraft:cut_sandstone_slab","minecraft:cut_red_sandstone_slab"],"minecraft:carpets":["minecraft:white_carpet","minecraft:orange_carpet","minecraft:magenta_carpet","minecraft:light_blue_carpet","minecraft:yellow_carpet","minecraft:lime_carpet","minecraft:pink_carpet","minecraft:gray_carpet","minecraft:light_gray_carpet","minecraft:cyan_carpet","minecraft:purple_carpet","minecraft:blue_carpet","minecraft:brown_carpet","minecraft:green_carpet","minecraft:red_carpet","minecraft:black_carpet"],"minecraft:stairs":["minecraft:oak_stairs","minecraft:cobblestone_stairs","minecraft:spruce_stairs","minecraft:sandstone_stairs","minecraft:acacia_stairs","minecraft:jungle_stairs","minecraft:birch_stairs","minecraft:dark_oak_stairs","minecraft:nether_brick_stairs","minecraft:stone_brick_stairs","minecraft:brick_stairs","minecraft:purpur_stairs","minecraft:quartz_stairs","minecraft:red_sandstone_stairs","minecraft:prismarine_brick_stairs","minecraft:prismarine_stairs","minecraft:dark_prismarine_stairs","minecraft:polished_granite_stairs","minecraft:smooth_red_sandstone_stairs","minecraft:mossy_stone_brick_stairs","minecraft:polished_diorite_stairs","minecraft:mossy_cobblestone_stairs","minecraft:end_stone_brick_stairs","minecraft:stone_stairs","minecraft:smooth_sandstone_stairs","minecraft:smooth_quartz_stairs","minecraft:granite_stairs","minecraft:andesite_stairs","minecraft:red_nether_brick_stairs","minecraft:polished_andesite_stairs","minecraft:diorite_stairs"],"minecraft:wooden_doors":["minecraft:oak_door","minecraft:spruce_door","minecraft:birch_door","minecraft:jungle_door","minecraft:acacia_door","minecraft:dark_oak_door"],"minecraft:jungle_logs":["minecraft:jungle_log","minecraft:jungle_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood"],"minecraft:planks":["minecraft:oak_planks","minecraft:spruce_planks","minecraft:birch_planks","minecraft:jungle_planks","minecraft:acacia_planks","minecraft:dark_oak_planks"],"minecraft:wall_corals":["minecraft:tube_coral_wall_fan","minecraft:brain_coral_wall_fan","minecraft:bubble_coral_wall_fan","minecraft:fire_coral_wall_fan","minecraft:horn_coral_wall_fan"],"minecraft:acacia_logs":["minecraft:acacia_log","minecraft:acacia_wood","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood"],"minecraft:wither_immune":["minecraft:barrier","minecraft:bedrock","minecraft:end_portal","minecraft:end_portal_frame","minecraft:end_gateway","minecraft:command_block","minecraft:repeating_command_block","minecraft:chain_command_block","minecraft:structure_block","minecraft:jigsaw","minecraft:moving_piston"],"minecraft:flower_pots":["minecraft:flower_pot","minecraft:potted_poppy","minecraft:potted_blue_orchid","minecraft:potted_allium","minecraft:potted_azure_bluet","minecraft:potted_red_tulip","minecraft:potted_orange_tulip","minecraft:potted_white_tulip","minecraft:potted_pink_tulip","minecraft:potted_oxeye_daisy","minecraft:potted_dandelion","minecraft:potted_oak_sapling","minecraft:potted_spruce_sapling","minecraft:potted_birch_sapling","minecraft:potted_jungle_sapling","minecraft:potted_acacia_sapling","minecraft:potted_dark_oak_sapling","minecraft:potted_red_mushroom","minecraft:potted_brown_mushroom","minecraft:potted_dead_bush","minecraft:potted_fern","minecraft:potted_cactus","minecraft:potted_cornflower","minecraft:potted_lily_of_the_valley","minecraft:potted_wither_rose","minecraft:potted_bamboo"],"minecraft:stone_bricks":["minecraft:stone_bricks","minecraft:mossy_stone_bricks","minecraft:cracked_stone_bricks","minecraft:chiseled_stone_bricks"],"minecraft:enderman_holdable":["minecraft:grass_block","minecraft:dirt","minecraft:coarse_dirt","minecraft:podzol","minecraft:sand","minecraft:red_sand","minecraft:gravel","minecraft:brown_mushroom","minecraft:red_mushroom","minecraft:tnt","minecraft:cactus","minecraft:clay","minecraft:pumpkin","minecraft:carved_pumpkin","minecraft:melon","minecraft:mycelium","minecraft:netherrack","minecraft:dandelion","minecraft:poppy","minecraft:blue_orchid","minecraft:allium","minecraft:azure_bluet","minecraft:red_tulip","minecraft:orange_tulip","minecraft:white_tulip","minecraft:pink_tulip","minecraft:oxeye_daisy","minecraft:cornflower","minecraft:lily_of_the_valley","minecraft:wither_rose"],"minecraft:spruce_logs":["minecraft:spruce_log","minecraft:spruce_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood"],"minecraft:wooden_slabs":["minecraft:oak_slab","minecraft:spruce_slab","minecraft:birch_slab","minecraft:jungle_slab","minecraft:acacia_slab","minecraft:dark_oak_slab"],"minecraft:coral_blocks":["minecraft:tube_coral_block","minecraft:brain_coral_block","minecraft:bubble_coral_block","minecraft:fire_coral_block","minecraft:horn_coral_block"],"minecraft:signs":["minecraft:oak_sign","minecraft:spruce_sign","minecraft:birch_sign","minecraft:acacia_sign","minecraft:jungle_sign","minecraft:dark_oak_sign","minecraft:oak_wall_sign","minecraft:spruce_wall_sign","minecraft:birch_wall_sign","minecraft:acacia_wall_sign","minecraft:jungle_wall_sign","minecraft:dark_oak_wall_sign"],"minecraft:dark_oak_logs":["minecraft:dark_oak_log","minecraft:dark_oak_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood"],"minecraft:sand":["minecraft:sand","minecraft:red_sand"],"minecraft:valid_spawn":["minecraft:grass_block","minecraft:podzol"],"minecraft:underwater_bonemeals":["minecraft:seagrass","minecraft:tube_coral_fan","minecraft:brain_coral_fan","minecraft:bubble_coral_fan","minecraft:fire_coral_fan","minecraft:horn_coral_fan","minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral","minecraft:tube_coral_wall_fan","minecraft:brain_coral_wall_fan","minecraft:bubble_coral_wall_fan","minecraft:fire_coral_wall_fan","minecraft:horn_coral_wall_fan"],"minecraft:oak_logs":["minecraft:oak_log","minecraft:oak_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood"],"minecraft:buttons":["minecraft:stone_button","minecraft:oak_button","minecraft:spruce_button","minecraft:birch_button","minecraft:jungle_button","minecraft:acacia_button","minecraft:dark_oak_button"],"minecraft:wooden_pressure_plates":["minecraft:oak_pressure_plate","minecraft:spruce_pressure_plate","minecraft:birch_pressure_plate","minecraft:jungle_pressure_plate","minecraft:acacia_pressure_plate","minecraft:dark_oak_pressure_plate"],"minecraft:beds":["minecraft:red_bed","minecraft:black_bed","minecraft:blue_bed","minecraft:brown_bed","minecraft:cyan_bed","minecraft:gray_bed","minecraft:green_bed","minecraft:light_blue_bed","minecraft:light_gray_bed","minecraft:lime_bed","minecraft:magenta_bed","minecraft:orange_bed","minecraft:pink_bed","minecraft:purple_bed","minecraft:white_bed","minecraft:yellow_bed"],"minecraft:walls":["minecraft:cobblestone_wall","minecraft:mossy_cobblestone_wall","minecraft:brick_wall","minecraft:prismarine_wall","minecraft:red_sandstone_wall","minecraft:mossy_stone_brick_wall","minecraft:granite_wall","minecraft:stone_brick_wall","minecraft:nether_brick_wall","minecraft:andesite_wall","minecraft:red_nether_brick_wall","minecraft:sandstone_wall","minecraft:end_stone_brick_wall","minecraft:diorite_wall"],"minecraft:rails":["minecraft:rail","minecraft:powered_rail","minecraft:detector_rail","minecraft:activator_rail"],"minecraft:birch_logs":["minecraft:birch_log","minecraft:birch_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood"],"minecraft:wooden_trapdoors":["minecraft:acacia_trapdoor","minecraft:birch_trapdoor","minecraft:dark_oak_trapdoor","minecraft:jungle_trapdoor","minecraft:oak_trapdoor","minecraft:spruce_trapdoor"],"minecraft:wooden_fences":["minecraft:oak_fence","minecraft:acacia_fence","minecraft:dark_oak_fence","minecraft:spruce_fence","minecraft:birch_fence","minecraft:jungle_fence"],"minecraft:saplings":["minecraft:oak_sapling","minecraft:spruce_sapling","minecraft:birch_sapling","minecraft:jungle_sapling","minecraft:acacia_sapling","minecraft:dark_oak_sapling"],"minecraft:small_flowers":["minecraft:dandelion","minecraft:poppy","minecraft:blue_orchid","minecraft:allium","minecraft:azure_bluet","minecraft:red_tulip","minecraft:orange_tulip","minecraft:white_tulip","minecraft:pink_tulip","minecraft:oxeye_daisy","minecraft:cornflower","minecraft:lily_of_the_valley","minecraft:wither_rose"],"minecraft:bamboo_plantable_on":["minecraft:bamboo","minecraft:bamboo_sapling","minecraft:gravel","minecraft:sand","minecraft:red_sand","minecraft:dirt","minecraft:grass_block","minecraft:podzol","minecraft:coarse_dirt","minecraft:mycelium"],"minecraft:ice":["minecraft:ice","minecraft:packed_ice","minecraft:blue_ice","minecraft:frosted_ice"],"minecraft:wooden_stairs":["minecraft:oak_stairs","minecraft:spruce_stairs","minecraft:birch_stairs","minecraft:jungle_stairs","minecraft:acacia_stairs","minecraft:dark_oak_stairs"],"minecraft:anvil":["minecraft:anvil","minecraft:chipped_anvil","minecraft:damaged_anvil"],"minecraft:logs":["minecraft:dark_oak_log","minecraft:dark_oak_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood","minecraft:oak_log","minecraft:oak_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood","minecraft:acacia_log","minecraft:acacia_wood","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood","minecraft:birch_log","minecraft:birch_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood","minecraft:jungle_log","minecraft:jungle_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood","minecraft:spruce_log","minecraft:spruce_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood"],"minecraft:corals":["minecraft:tube_coral_fan","minecraft:brain_coral_fan","minecraft:bubble_coral_fan","minecraft:fire_coral_fan","minecraft:horn_coral_fan","minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral"],"minecraft:wooden_buttons":["minecraft:oak_button","minecraft:spruce_button","minecraft:birch_button","minecraft:jungle_button","minecraft:acacia_button","minecraft:dark_oak_button"],"minecraft:wool":["minecraft:white_wool","minecraft:orange_wool","minecraft:magenta_wool","minecraft:light_blue_wool","minecraft:yellow_wool","minecraft:lime_wool","minecraft:pink_wool","minecraft:gray_wool","minecraft:light_gray_wool","minecraft:cyan_wool","minecraft:purple_wool","minecraft:blue_wool","minecraft:brown_wool","minecraft:green_wool","minecraft:red_wool","minecraft:black_wool"],"minecraft:coral_plants":["minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral"],"minecraft:banners":["minecraft:white_banner","minecraft:orange_banner","minecraft:magenta_banner","minecraft:light_blue_banner","minecraft:yellow_banner","minecraft:lime_banner","minecraft:pink_banner","minecraft:gray_banner","minecraft:light_gray_banner","minecraft:cyan_banner","minecraft:purple_banner","minecraft:blue_banner","minecraft:brown_banner","minecraft:green_banner","minecraft:red_banner","minecraft:black_banner","minecraft:white_wall_banner","minecraft:orange_wall_banner","minecraft:magenta_wall_banner","minecraft:light_blue_wall_banner","minecraft:yellow_wall_banner","minecraft:lime_wall_banner","minecraft:pink_wall_banner","minecraft:gray_wall_banner","minecraft:light_gray_wall_banner","minecraft:cyan_wall_banner","minecraft:purple_wall_banner","minecraft:blue_wall_banner","minecraft:brown_wall_banner","minecraft:green_wall_banner","minecraft:red_wall_banner","minecraft:black_wall_banner"],"minecraft:dragon_immune":["minecraft:barrier","minecraft:bedrock","minecraft:end_portal","minecraft:end_portal_frame","minecraft:end_gateway","minecraft:command_block","minecraft:repeating_command_block","minecraft:chain_command_block","minecraft:structure_block","minecraft:jigsaw","minecraft:moving_piston","minecraft:obsidian","minecraft:end_stone","minecraft:iron_bars"],"minecraft:doors":["minecraft:iron_door","minecraft:oak_door","minecraft:spruce_door","minecraft:birch_door","minecraft:jungle_door","minecraft:acacia_door","minecraft:dark_oak_door"],"minecraft:fences":["minecraft:nether_brick_fence","minecraft:oak_fence","minecraft:acacia_fence","minecraft:dark_oak_fence","minecraft:spruce_fence","minecraft:birch_fence","minecraft:jungle_fence"],"minecraft:wall_signs":["minecraft:oak_wall_sign","minecraft:spruce_wall_sign","minecraft:birch_wall_sign","minecraft:acacia_wall_sign","minecraft:jungle_wall_sign","minecraft:dark_oak_wall_sign"],"minecraft:standing_signs":["minecraft:oak_sign","minecraft:spruce_sign","minecraft:birch_sign","minecraft:acacia_sign","minecraft:jungle_sign","minecraft:dark_oak_sign"],"minecraft:dirt_like":["minecraft:dirt","minecraft:grass_block","minecraft:podzol","minecraft:coarse_dirt","minecraft:mycelium"],"minecraft:impermeable":["minecraft:glass","minecraft:white_stained_glass","minecraft:orange_stained_glass","minecraft:magenta_stained_glass","minecraft:light_blue_stained_glass","minecraft:yellow_stained_glass","minecraft:lime_stained_glass","minecraft:pink_stained_glass","minecraft:gray_stained_glass","minecraft:light_gray_stained_glass","minecraft:cyan_stained_glass","minecraft:purple_stained_glass","minecraft:blue_stained_glass","minecraft:brown_stained_glass","minecraft:green_stained_glass","minecraft:red_stained_glass","minecraft:black_stained_glass"],"minecraft:trapdoors":["minecraft:iron_trapdoor","minecraft:acacia_trapdoor","minecraft:birch_trapdoor","minecraft:dark_oak_trapdoor","minecraft:jungle_trapdoor","minecraft:oak_trapdoor","minecraft:spruce_trapdoor"],"minecraft:leaves":["minecraft:jungle_leaves","minecraft:oak_leaves","minecraft:spruce_leaves","minecraft:dark_oak_leaves","minecraft:acacia_leaves","minecraft:birch_leaves"]},"itemtags":{"minecraft:boats":["minecraft:oak_boat","minecraft:spruce_boat","minecraft:birch_boat","minecraft:jungle_boat","minecraft:acacia_boat","minecraft:dark_oak_boat"],"minecraft:banners":["minecraft:white_banner","minecraft:orange_banner","minecraft:magenta_banner","minecraft:light_blue_banner","minecraft:yellow_banner","minecraft:lime_banner","minecraft:pink_banner","minecraft:gray_banner","minecraft:light_gray_banner","minecraft:cyan_banner","minecraft:purple_banner","minecraft:blue_banner","minecraft:brown_banner","minecraft:green_banner","minecraft:red_banner","minecraft:black_banner"],"minecraft:arrows":["minecraft:arrow","minecraft:tipped_arrow","minecraft:spectral_arrow"],"minecraft:coals":["minecraft:coal","minecraft:charcoal"],"minecraft:music_discs":["minecraft:music_disc_13","minecraft:music_disc_cat","minecraft:music_disc_blocks","minecraft:music_disc_chirp","minecraft:music_disc_far","minecraft:music_disc_mall","minecraft:music_disc_mellohi","minecraft:music_disc_stal","minecraft:music_disc_strad","minecraft:music_disc_ward","minecraft:music_disc_11","minecraft:music_disc_wait"],"minecraft:fishes":["minecraft:cod","minecraft:cooked_cod","minecraft:salmon","minecraft:cooked_salmon","minecraft:pufferfish","minecraft:tropical_fish"]},"entitytags":{"minecraft:raiders":["minecraft:evoker","minecraft:pillager","minecraft:ravager","minecraft:vindicator","minecraft:illusioner","minecraft:witch"],"minecraft:skeletons":["minecraft:skeleton","minecraft:stray","minecraft:wither_skeleton"]}} \ No newline at end of file diff --git a/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1968.json b/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1968.json new file mode 100644 index 000000000..f99217273 --- /dev/null +++ b/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1968.json @@ -0,0 +1 @@ +{"blocks":{"minecraft:acacia_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_button[face=wall,facing=north,powered=false]"},"minecraft:acacia_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:acacia_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:acacia_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:acacia_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_leaves[distance=7,persistent=false]"},"minecraft:acacia_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:acacia_log[axis=y]"},"minecraft:acacia_planks":{"properties":{},"defaultstate":"minecraft:acacia_planks"},"minecraft:acacia_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_pressure_plate[powered=false]"},"minecraft:acacia_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:acacia_sapling[stage=0]"},"minecraft:acacia_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_sign[rotation=0,waterlogged=false]"},"minecraft:acacia_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_slab[type=bottom,waterlogged=false]"},"minecraft:acacia_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:acacia_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:acacia_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_wall_sign[facing=north,waterlogged=false]"},"minecraft:acacia_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:acacia_wood[axis=y]"},"minecraft:activator_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:activator_rail[powered=false,shape=north_south]"},"minecraft:air":{"properties":{},"defaultstate":"minecraft:air"},"minecraft:allium":{"properties":{},"defaultstate":"minecraft:allium"},"minecraft:andesite":{"properties":{},"defaultstate":"minecraft:andesite"},"minecraft:andesite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:andesite_slab[type=bottom,waterlogged=false]"},"minecraft:andesite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:andesite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:andesite_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:andesite_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:anvil[facing=north]"},"minecraft:attached_melon_stem":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:attached_melon_stem[facing=north]"},"minecraft:attached_pumpkin_stem":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:attached_pumpkin_stem[facing=north]"},"minecraft:azure_bluet":{"properties":{},"defaultstate":"minecraft:azure_bluet"},"minecraft:bamboo":{"properties":{"age":{"values":["0","1"],"type":"int"},"leaves":{"values":["none","small","large"],"type":"enum"},"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:bamboo[age=0,leaves=none,stage=0]"},"minecraft:bamboo_sapling":{"properties":{},"defaultstate":"minecraft:bamboo_sapling"},"minecraft:barrel":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"open":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:barrel[facing=north,open=false]"},"minecraft:barrier":{"properties":{},"defaultstate":"minecraft:barrier"},"minecraft:beacon":{"properties":{},"defaultstate":"minecraft:beacon"},"minecraft:bedrock":{"properties":{},"defaultstate":"minecraft:bedrock"},"minecraft:beetroots":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:beetroots[age=0]"},"minecraft:bell":{"properties":{"attachment":{"values":["floor","ceiling","single_wall","double_wall"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:bell[attachment=floor,facing=north]"},"minecraft:birch_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_button[face=wall,facing=north,powered=false]"},"minecraft:birch_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:birch_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:birch_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:birch_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_leaves[distance=7,persistent=false]"},"minecraft:birch_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:birch_log[axis=y]"},"minecraft:birch_planks":{"properties":{},"defaultstate":"minecraft:birch_planks"},"minecraft:birch_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_pressure_plate[powered=false]"},"minecraft:birch_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:birch_sapling[stage=0]"},"minecraft:birch_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_sign[rotation=0,waterlogged=false]"},"minecraft:birch_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_slab[type=bottom,waterlogged=false]"},"minecraft:birch_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:birch_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:birch_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_wall_sign[facing=north,waterlogged=false]"},"minecraft:birch_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:birch_wood[axis=y]"},"minecraft:black_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:black_banner[rotation=0]"},"minecraft:black_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:black_bed[facing=north,occupied=false,part=foot]"},"minecraft:black_carpet":{"properties":{},"defaultstate":"minecraft:black_carpet"},"minecraft:black_concrete":{"properties":{},"defaultstate":"minecraft:black_concrete"},"minecraft:black_concrete_powder":{"properties":{},"defaultstate":"minecraft:black_concrete_powder"},"minecraft:black_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:black_glazed_terracotta[facing=north]"},"minecraft:black_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:black_shulker_box[facing=up]"},"minecraft:black_stained_glass":{"properties":{},"defaultstate":"minecraft:black_stained_glass"},"minecraft:black_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:black_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:black_terracotta":{"properties":{},"defaultstate":"minecraft:black_terracotta"},"minecraft:black_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:black_wall_banner[facing=north]"},"minecraft:black_wool":{"properties":{},"defaultstate":"minecraft:black_wool"},"minecraft:blast_furnace":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:blast_furnace[facing=north,lit=false]"},"minecraft:blue_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:blue_banner[rotation=0]"},"minecraft:blue_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:blue_bed[facing=north,occupied=false,part=foot]"},"minecraft:blue_carpet":{"properties":{},"defaultstate":"minecraft:blue_carpet"},"minecraft:blue_concrete":{"properties":{},"defaultstate":"minecraft:blue_concrete"},"minecraft:blue_concrete_powder":{"properties":{},"defaultstate":"minecraft:blue_concrete_powder"},"minecraft:blue_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:blue_glazed_terracotta[facing=north]"},"minecraft:blue_ice":{"properties":{},"defaultstate":"minecraft:blue_ice"},"minecraft:blue_orchid":{"properties":{},"defaultstate":"minecraft:blue_orchid"},"minecraft:blue_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:blue_shulker_box[facing=up]"},"minecraft:blue_stained_glass":{"properties":{},"defaultstate":"minecraft:blue_stained_glass"},"minecraft:blue_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:blue_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:blue_terracotta":{"properties":{},"defaultstate":"minecraft:blue_terracotta"},"minecraft:blue_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:blue_wall_banner[facing=north]"},"minecraft:blue_wool":{"properties":{},"defaultstate":"minecraft:blue_wool"},"minecraft:bone_block":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:bone_block[axis=y]"},"minecraft:bookshelf":{"properties":{},"defaultstate":"minecraft:bookshelf"},"minecraft:brain_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral[waterlogged=true]"},"minecraft:brain_coral_block":{"properties":{},"defaultstate":"minecraft:brain_coral_block"},"minecraft:brain_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral_fan[waterlogged=true]"},"minecraft:brain_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:brewing_stand":{"properties":{"has_bottle_0":{"values":["true","false"],"type":"bool"},"has_bottle_1":{"values":["true","false"],"type":"bool"},"has_bottle_2":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]"},"minecraft:brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_slab[type=bottom,waterlogged=false]"},"minecraft:brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:bricks":{"properties":{},"defaultstate":"minecraft:bricks"},"minecraft:brown_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:brown_banner[rotation=0]"},"minecraft:brown_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:brown_bed[facing=north,occupied=false,part=foot]"},"minecraft:brown_carpet":{"properties":{},"defaultstate":"minecraft:brown_carpet"},"minecraft:brown_concrete":{"properties":{},"defaultstate":"minecraft:brown_concrete"},"minecraft:brown_concrete_powder":{"properties":{},"defaultstate":"minecraft:brown_concrete_powder"},"minecraft:brown_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:brown_glazed_terracotta[facing=north]"},"minecraft:brown_mushroom":{"properties":{},"defaultstate":"minecraft:brown_mushroom"},"minecraft:brown_mushroom_block":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:brown_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:brown_shulker_box[facing=up]"},"minecraft:brown_stained_glass":{"properties":{},"defaultstate":"minecraft:brown_stained_glass"},"minecraft:brown_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brown_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:brown_terracotta":{"properties":{},"defaultstate":"minecraft:brown_terracotta"},"minecraft:brown_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:brown_wall_banner[facing=north]"},"minecraft:brown_wool":{"properties":{},"defaultstate":"minecraft:brown_wool"},"minecraft:bubble_column":{"properties":{"drag":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_column[drag=true]"},"minecraft:bubble_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral[waterlogged=true]"},"minecraft:bubble_coral_block":{"properties":{},"defaultstate":"minecraft:bubble_coral_block"},"minecraft:bubble_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral_fan[waterlogged=true]"},"minecraft:bubble_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:cactus":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:cactus[age=0]"},"minecraft:cake":{"properties":{"bites":{"values":["0","1","2","3","4","5","6"],"type":"int"}},"defaultstate":"minecraft:cake[bites=0]"},"minecraft:campfire":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"},"signal_fire":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:campfire[facing=north,lit=true,signal_fire=false,waterlogged=false]"},"minecraft:carrots":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:carrots[age=0]"},"minecraft:cartography_table":{"properties":{},"defaultstate":"minecraft:cartography_table"},"minecraft:carved_pumpkin":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:carved_pumpkin[facing=north]"},"minecraft:cauldron":{"properties":{"level":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:cauldron[level=0]"},"minecraft:cave_air":{"properties":{},"defaultstate":"minecraft:cave_air"},"minecraft:chain_command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:chain_command_block[conditional=false,facing=north]"},"minecraft:chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"type":{"values":["single","left","right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:chest[facing=north,type=single,waterlogged=false]"},"minecraft:chipped_anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:chipped_anvil[facing=north]"},"minecraft:chiseled_quartz_block":{"properties":{},"defaultstate":"minecraft:chiseled_quartz_block"},"minecraft:chiseled_red_sandstone":{"properties":{},"defaultstate":"minecraft:chiseled_red_sandstone"},"minecraft:chiseled_sandstone":{"properties":{},"defaultstate":"minecraft:chiseled_sandstone"},"minecraft:chiseled_stone_bricks":{"properties":{},"defaultstate":"minecraft:chiseled_stone_bricks"},"minecraft:chorus_flower":{"properties":{"age":{"values":["0","1","2","3","4","5"],"type":"int"}},"defaultstate":"minecraft:chorus_flower[age=0]"},"minecraft:chorus_plant":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]"},"minecraft:clay":{"properties":{},"defaultstate":"minecraft:clay"},"minecraft:coal_block":{"properties":{},"defaultstate":"minecraft:coal_block"},"minecraft:coal_ore":{"properties":{},"defaultstate":"minecraft:coal_ore"},"minecraft:coarse_dirt":{"properties":{},"defaultstate":"minecraft:coarse_dirt"},"minecraft:cobblestone":{"properties":{},"defaultstate":"minecraft:cobblestone"},"minecraft:cobblestone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_slab[type=bottom,waterlogged=false]"},"minecraft:cobblestone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:cobblestone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:cobweb":{"properties":{},"defaultstate":"minecraft:cobweb"},"minecraft:cocoa":{"properties":{"age":{"values":["0","1","2"],"type":"int"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cocoa[age=0,facing=north]"},"minecraft:command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:command_block[conditional=false,facing=north]"},"minecraft:comparator":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"mode":{"values":["compare","subtract"],"type":"enum"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:comparator[facing=north,mode=compare,powered=false]"},"minecraft:composter":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8"],"type":"int"}},"defaultstate":"minecraft:composter[level=0]"},"minecraft:conduit":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:conduit[waterlogged=true]"},"minecraft:cornflower":{"properties":{},"defaultstate":"minecraft:cornflower"},"minecraft:cracked_stone_bricks":{"properties":{},"defaultstate":"minecraft:cracked_stone_bricks"},"minecraft:crafting_table":{"properties":{},"defaultstate":"minecraft:crafting_table"},"minecraft:creeper_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:creeper_head[rotation=0]"},"minecraft:creeper_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:creeper_wall_head[facing=north]"},"minecraft:cut_red_sandstone":{"properties":{},"defaultstate":"minecraft:cut_red_sandstone"},"minecraft:cut_red_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cut_red_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:cut_sandstone":{"properties":{},"defaultstate":"minecraft:cut_sandstone"},"minecraft:cut_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cut_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:cyan_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:cyan_banner[rotation=0]"},"minecraft:cyan_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:cyan_bed[facing=north,occupied=false,part=foot]"},"minecraft:cyan_carpet":{"properties":{},"defaultstate":"minecraft:cyan_carpet"},"minecraft:cyan_concrete":{"properties":{},"defaultstate":"minecraft:cyan_concrete"},"minecraft:cyan_concrete_powder":{"properties":{},"defaultstate":"minecraft:cyan_concrete_powder"},"minecraft:cyan_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cyan_glazed_terracotta[facing=north]"},"minecraft:cyan_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:cyan_shulker_box[facing=up]"},"minecraft:cyan_stained_glass":{"properties":{},"defaultstate":"minecraft:cyan_stained_glass"},"minecraft:cyan_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cyan_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:cyan_terracotta":{"properties":{},"defaultstate":"minecraft:cyan_terracotta"},"minecraft:cyan_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cyan_wall_banner[facing=north]"},"minecraft:cyan_wool":{"properties":{},"defaultstate":"minecraft:cyan_wool"},"minecraft:damaged_anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:damaged_anvil[facing=north]"},"minecraft:dandelion":{"properties":{},"defaultstate":"minecraft:dandelion"},"minecraft:dark_oak_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_button[face=wall,facing=north,powered=false]"},"minecraft:dark_oak_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:dark_oak_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:dark_oak_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:dark_oak_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_leaves[distance=7,persistent=false]"},"minecraft:dark_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:dark_oak_log[axis=y]"},"minecraft:dark_oak_planks":{"properties":{},"defaultstate":"minecraft:dark_oak_planks"},"minecraft:dark_oak_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_pressure_plate[powered=false]"},"minecraft:dark_oak_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:dark_oak_sapling[stage=0]"},"minecraft:dark_oak_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_sign[rotation=0,waterlogged=false]"},"minecraft:dark_oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_slab[type=bottom,waterlogged=false]"},"minecraft:dark_oak_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:dark_oak_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:dark_oak_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_wall_sign[facing=north,waterlogged=false]"},"minecraft:dark_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:dark_oak_wood[axis=y]"},"minecraft:dark_prismarine":{"properties":{},"defaultstate":"minecraft:dark_prismarine"},"minecraft:dark_prismarine_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_prismarine_slab[type=bottom,waterlogged=false]"},"minecraft:dark_prismarine_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_prismarine_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:daylight_detector":{"properties":{"inverted":{"values":["true","false"],"type":"bool"},"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:daylight_detector[inverted=false,power=0]"},"minecraft:dead_brain_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral[waterlogged=true]"},"minecraft:dead_brain_coral_block":{"properties":{},"defaultstate":"minecraft:dead_brain_coral_block"},"minecraft:dead_brain_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral_fan[waterlogged=true]"},"minecraft:dead_brain_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_bubble_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral[waterlogged=true]"},"minecraft:dead_bubble_coral_block":{"properties":{},"defaultstate":"minecraft:dead_bubble_coral_block"},"minecraft:dead_bubble_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral_fan[waterlogged=true]"},"minecraft:dead_bubble_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_bush":{"properties":{},"defaultstate":"minecraft:dead_bush"},"minecraft:dead_fire_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral[waterlogged=true]"},"minecraft:dead_fire_coral_block":{"properties":{},"defaultstate":"minecraft:dead_fire_coral_block"},"minecraft:dead_fire_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral_fan[waterlogged=true]"},"minecraft:dead_fire_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_horn_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral[waterlogged=true]"},"minecraft:dead_horn_coral_block":{"properties":{},"defaultstate":"minecraft:dead_horn_coral_block"},"minecraft:dead_horn_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral_fan[waterlogged=true]"},"minecraft:dead_horn_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_tube_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral[waterlogged=true]"},"minecraft:dead_tube_coral_block":{"properties":{},"defaultstate":"minecraft:dead_tube_coral_block"},"minecraft:dead_tube_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral_fan[waterlogged=true]"},"minecraft:dead_tube_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:detector_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:detector_rail[powered=false,shape=north_south]"},"minecraft:diamond_block":{"properties":{},"defaultstate":"minecraft:diamond_block"},"minecraft:diamond_ore":{"properties":{},"defaultstate":"minecraft:diamond_ore"},"minecraft:diorite":{"properties":{},"defaultstate":"minecraft:diorite"},"minecraft:diorite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:diorite_slab[type=bottom,waterlogged=false]"},"minecraft:diorite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:diorite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:diorite_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:diorite_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:dirt":{"properties":{},"defaultstate":"minecraft:dirt"},"minecraft:dispenser":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"triggered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dispenser[facing=north,triggered=false]"},"minecraft:dragon_egg":{"properties":{},"defaultstate":"minecraft:dragon_egg"},"minecraft:dragon_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:dragon_head[rotation=0]"},"minecraft:dragon_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:dragon_wall_head[facing=north]"},"minecraft:dried_kelp_block":{"properties":{},"defaultstate":"minecraft:dried_kelp_block"},"minecraft:dropper":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"triggered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dropper[facing=north,triggered=false]"},"minecraft:emerald_block":{"properties":{},"defaultstate":"minecraft:emerald_block"},"minecraft:emerald_ore":{"properties":{},"defaultstate":"minecraft:emerald_ore"},"minecraft:enchanting_table":{"properties":{},"defaultstate":"minecraft:enchanting_table"},"minecraft:end_gateway":{"properties":{},"defaultstate":"minecraft:end_gateway"},"minecraft:end_portal":{"properties":{},"defaultstate":"minecraft:end_portal"},"minecraft:end_portal_frame":{"properties":{"eye":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:end_portal_frame[eye=false,facing=north]"},"minecraft:end_rod":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:end_rod[facing=up]"},"minecraft:end_stone":{"properties":{},"defaultstate":"minecraft:end_stone"},"minecraft:end_stone_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:end_stone_brick_slab[type=bottom,waterlogged=false]"},"minecraft:end_stone_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:end_stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:end_stone_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:end_stone_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:end_stone_bricks":{"properties":{},"defaultstate":"minecraft:end_stone_bricks"},"minecraft:ender_chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:ender_chest[facing=north,waterlogged=false]"},"minecraft:farmland":{"properties":{"moisture":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:farmland[moisture=0]"},"minecraft:fern":{"properties":{},"defaultstate":"minecraft:fern"},"minecraft:fire":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire[age=0,east=false,north=false,south=false,up=false,west=false]"},"minecraft:fire_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral[waterlogged=true]"},"minecraft:fire_coral_block":{"properties":{},"defaultstate":"minecraft:fire_coral_block"},"minecraft:fire_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral_fan[waterlogged=true]"},"minecraft:fire_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:fletching_table":{"properties":{},"defaultstate":"minecraft:fletching_table"},"minecraft:flower_pot":{"properties":{},"defaultstate":"minecraft:flower_pot"},"minecraft:frosted_ice":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:frosted_ice[age=0]"},"minecraft:furnace":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:furnace[facing=north,lit=false]"},"minecraft:glass":{"properties":{},"defaultstate":"minecraft:glass"},"minecraft:glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:glowstone":{"properties":{},"defaultstate":"minecraft:glowstone"},"minecraft:gold_block":{"properties":{},"defaultstate":"minecraft:gold_block"},"minecraft:gold_ore":{"properties":{},"defaultstate":"minecraft:gold_ore"},"minecraft:granite":{"properties":{},"defaultstate":"minecraft:granite"},"minecraft:granite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:granite_slab[type=bottom,waterlogged=false]"},"minecraft:granite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:granite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:granite_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:granite_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:grass":{"properties":{},"defaultstate":"minecraft:grass"},"minecraft:grass_block":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:grass_block[snowy=false]"},"minecraft:grass_path":{"properties":{},"defaultstate":"minecraft:grass_path"},"minecraft:gravel":{"properties":{},"defaultstate":"minecraft:gravel"},"minecraft:gray_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:gray_banner[rotation=0]"},"minecraft:gray_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:gray_bed[facing=north,occupied=false,part=foot]"},"minecraft:gray_carpet":{"properties":{},"defaultstate":"minecraft:gray_carpet"},"minecraft:gray_concrete":{"properties":{},"defaultstate":"minecraft:gray_concrete"},"minecraft:gray_concrete_powder":{"properties":{},"defaultstate":"minecraft:gray_concrete_powder"},"minecraft:gray_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:gray_glazed_terracotta[facing=north]"},"minecraft:gray_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:gray_shulker_box[facing=up]"},"minecraft:gray_stained_glass":{"properties":{},"defaultstate":"minecraft:gray_stained_glass"},"minecraft:gray_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:gray_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:gray_terracotta":{"properties":{},"defaultstate":"minecraft:gray_terracotta"},"minecraft:gray_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:gray_wall_banner[facing=north]"},"minecraft:gray_wool":{"properties":{},"defaultstate":"minecraft:gray_wool"},"minecraft:green_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:green_banner[rotation=0]"},"minecraft:green_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:green_bed[facing=north,occupied=false,part=foot]"},"minecraft:green_carpet":{"properties":{},"defaultstate":"minecraft:green_carpet"},"minecraft:green_concrete":{"properties":{},"defaultstate":"minecraft:green_concrete"},"minecraft:green_concrete_powder":{"properties":{},"defaultstate":"minecraft:green_concrete_powder"},"minecraft:green_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:green_glazed_terracotta[facing=north]"},"minecraft:green_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:green_shulker_box[facing=up]"},"minecraft:green_stained_glass":{"properties":{},"defaultstate":"minecraft:green_stained_glass"},"minecraft:green_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:green_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:green_terracotta":{"properties":{},"defaultstate":"minecraft:green_terracotta"},"minecraft:green_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:green_wall_banner[facing=north]"},"minecraft:green_wool":{"properties":{},"defaultstate":"minecraft:green_wool"},"minecraft:grindstone":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:grindstone[face=wall,facing=north]"},"minecraft:hay_block":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:hay_block[axis=y]"},"minecraft:heavy_weighted_pressure_plate":{"properties":{"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:heavy_weighted_pressure_plate[power=0]"},"minecraft:hopper":{"properties":{"enabled":{"values":["true","false"],"type":"bool"},"facing":{"values":["down","north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:hopper[enabled=true,facing=down]"},"minecraft:horn_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral[waterlogged=true]"},"minecraft:horn_coral_block":{"properties":{},"defaultstate":"minecraft:horn_coral_block"},"minecraft:horn_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral_fan[waterlogged=true]"},"minecraft:horn_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:ice":{"properties":{},"defaultstate":"minecraft:ice"},"minecraft:infested_chiseled_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_chiseled_stone_bricks"},"minecraft:infested_cobblestone":{"properties":{},"defaultstate":"minecraft:infested_cobblestone"},"minecraft:infested_cracked_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_cracked_stone_bricks"},"minecraft:infested_mossy_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_mossy_stone_bricks"},"minecraft:infested_stone":{"properties":{},"defaultstate":"minecraft:infested_stone"},"minecraft:infested_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_stone_bricks"},"minecraft:iron_bars":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_bars[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:iron_block":{"properties":{},"defaultstate":"minecraft:iron_block"},"minecraft:iron_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:iron_ore":{"properties":{},"defaultstate":"minecraft:iron_ore"},"minecraft:iron_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:jack_o_lantern":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:jack_o_lantern[facing=north]"},"minecraft:jigsaw":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:jigsaw[facing=up]"},"minecraft:jukebox":{"properties":{"has_record":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jukebox[has_record=false]"},"minecraft:jungle_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_button[face=wall,facing=north,powered=false]"},"minecraft:jungle_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:jungle_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:jungle_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:jungle_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_leaves[distance=7,persistent=false]"},"minecraft:jungle_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:jungle_log[axis=y]"},"minecraft:jungle_planks":{"properties":{},"defaultstate":"minecraft:jungle_planks"},"minecraft:jungle_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_pressure_plate[powered=false]"},"minecraft:jungle_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:jungle_sapling[stage=0]"},"minecraft:jungle_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_sign[rotation=0,waterlogged=false]"},"minecraft:jungle_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_slab[type=bottom,waterlogged=false]"},"minecraft:jungle_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:jungle_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:jungle_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_wall_sign[facing=north,waterlogged=false]"},"minecraft:jungle_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:jungle_wood[axis=y]"},"minecraft:kelp":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25"],"type":"int"}},"defaultstate":"minecraft:kelp[age=0]"},"minecraft:kelp_plant":{"properties":{},"defaultstate":"minecraft:kelp_plant"},"minecraft:ladder":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:ladder[facing=north,waterlogged=false]"},"minecraft:lantern":{"properties":{"hanging":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lantern[hanging=false]"},"minecraft:lapis_block":{"properties":{},"defaultstate":"minecraft:lapis_block"},"minecraft:lapis_ore":{"properties":{},"defaultstate":"minecraft:lapis_ore"},"minecraft:large_fern":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:large_fern[half=lower]"},"minecraft:lava":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:lava[level=0]"},"minecraft:lectern":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"has_book":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lectern[facing=north,has_book=false,powered=false]"},"minecraft:lever":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lever[face=wall,facing=north,powered=false]"},"minecraft:light_blue_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_blue_banner[rotation=0]"},"minecraft:light_blue_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:light_blue_bed[facing=north,occupied=false,part=foot]"},"minecraft:light_blue_carpet":{"properties":{},"defaultstate":"minecraft:light_blue_carpet"},"minecraft:light_blue_concrete":{"properties":{},"defaultstate":"minecraft:light_blue_concrete"},"minecraft:light_blue_concrete_powder":{"properties":{},"defaultstate":"minecraft:light_blue_concrete_powder"},"minecraft:light_blue_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_blue_glazed_terracotta[facing=north]"},"minecraft:light_blue_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:light_blue_shulker_box[facing=up]"},"minecraft:light_blue_stained_glass":{"properties":{},"defaultstate":"minecraft:light_blue_stained_glass"},"minecraft:light_blue_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:light_blue_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:light_blue_terracotta":{"properties":{},"defaultstate":"minecraft:light_blue_terracotta"},"minecraft:light_blue_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_blue_wall_banner[facing=north]"},"minecraft:light_blue_wool":{"properties":{},"defaultstate":"minecraft:light_blue_wool"},"minecraft:light_gray_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_gray_banner[rotation=0]"},"minecraft:light_gray_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:light_gray_bed[facing=north,occupied=false,part=foot]"},"minecraft:light_gray_carpet":{"properties":{},"defaultstate":"minecraft:light_gray_carpet"},"minecraft:light_gray_concrete":{"properties":{},"defaultstate":"minecraft:light_gray_concrete"},"minecraft:light_gray_concrete_powder":{"properties":{},"defaultstate":"minecraft:light_gray_concrete_powder"},"minecraft:light_gray_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_gray_glazed_terracotta[facing=north]"},"minecraft:light_gray_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:light_gray_shulker_box[facing=up]"},"minecraft:light_gray_stained_glass":{"properties":{},"defaultstate":"minecraft:light_gray_stained_glass"},"minecraft:light_gray_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:light_gray_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:light_gray_terracotta":{"properties":{},"defaultstate":"minecraft:light_gray_terracotta"},"minecraft:light_gray_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_gray_wall_banner[facing=north]"},"minecraft:light_gray_wool":{"properties":{},"defaultstate":"minecraft:light_gray_wool"},"minecraft:light_weighted_pressure_plate":{"properties":{"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_weighted_pressure_plate[power=0]"},"minecraft:lilac":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:lilac[half=lower]"},"minecraft:lily_of_the_valley":{"properties":{},"defaultstate":"minecraft:lily_of_the_valley"},"minecraft:lily_pad":{"properties":{},"defaultstate":"minecraft:lily_pad"},"minecraft:lime_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:lime_banner[rotation=0]"},"minecraft:lime_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:lime_bed[facing=north,occupied=false,part=foot]"},"minecraft:lime_carpet":{"properties":{},"defaultstate":"minecraft:lime_carpet"},"minecraft:lime_concrete":{"properties":{},"defaultstate":"minecraft:lime_concrete"},"minecraft:lime_concrete_powder":{"properties":{},"defaultstate":"minecraft:lime_concrete_powder"},"minecraft:lime_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:lime_glazed_terracotta[facing=north]"},"minecraft:lime_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:lime_shulker_box[facing=up]"},"minecraft:lime_stained_glass":{"properties":{},"defaultstate":"minecraft:lime_stained_glass"},"minecraft:lime_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lime_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:lime_terracotta":{"properties":{},"defaultstate":"minecraft:lime_terracotta"},"minecraft:lime_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:lime_wall_banner[facing=north]"},"minecraft:lime_wool":{"properties":{},"defaultstate":"minecraft:lime_wool"},"minecraft:loom":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:loom[facing=north]"},"minecraft:magenta_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:magenta_banner[rotation=0]"},"minecraft:magenta_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:magenta_bed[facing=north,occupied=false,part=foot]"},"minecraft:magenta_carpet":{"properties":{},"defaultstate":"minecraft:magenta_carpet"},"minecraft:magenta_concrete":{"properties":{},"defaultstate":"minecraft:magenta_concrete"},"minecraft:magenta_concrete_powder":{"properties":{},"defaultstate":"minecraft:magenta_concrete_powder"},"minecraft:magenta_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:magenta_glazed_terracotta[facing=north]"},"minecraft:magenta_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:magenta_shulker_box[facing=up]"},"minecraft:magenta_stained_glass":{"properties":{},"defaultstate":"minecraft:magenta_stained_glass"},"minecraft:magenta_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:magenta_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:magenta_terracotta":{"properties":{},"defaultstate":"minecraft:magenta_terracotta"},"minecraft:magenta_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:magenta_wall_banner[facing=north]"},"minecraft:magenta_wool":{"properties":{},"defaultstate":"minecraft:magenta_wool"},"minecraft:magma_block":{"properties":{},"defaultstate":"minecraft:magma_block"},"minecraft:melon":{"properties":{},"defaultstate":"minecraft:melon"},"minecraft:melon_stem":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:melon_stem[age=0]"},"minecraft:mossy_cobblestone":{"properties":{},"defaultstate":"minecraft:mossy_cobblestone"},"minecraft:mossy_cobblestone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_cobblestone_slab[type=bottom,waterlogged=false]"},"minecraft:mossy_cobblestone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_cobblestone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:mossy_cobblestone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_cobblestone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:mossy_stone_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_stone_brick_slab[type=bottom,waterlogged=false]"},"minecraft:mossy_stone_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:mossy_stone_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_stone_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:mossy_stone_bricks":{"properties":{},"defaultstate":"minecraft:mossy_stone_bricks"},"minecraft:moving_piston":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"type":{"values":["normal","sticky"],"type":"enum"}},"defaultstate":"minecraft:moving_piston[facing=north,type=normal]"},"minecraft:mushroom_stem":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:mycelium":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mycelium[snowy=false]"},"minecraft:nether_brick_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:nether_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_slab[type=bottom,waterlogged=false]"},"minecraft:nether_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:nether_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:nether_bricks":{"properties":{},"defaultstate":"minecraft:nether_bricks"},"minecraft:nether_portal":{"properties":{"axis":{"values":["x","z"],"type":"enum"}},"defaultstate":"minecraft:nether_portal[axis=x]"},"minecraft:nether_quartz_ore":{"properties":{},"defaultstate":"minecraft:nether_quartz_ore"},"minecraft:nether_wart":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:nether_wart[age=0]"},"minecraft:nether_wart_block":{"properties":{},"defaultstate":"minecraft:nether_wart_block"},"minecraft:netherrack":{"properties":{},"defaultstate":"minecraft:netherrack"},"minecraft:note_block":{"properties":{"instrument":{"values":["harp","basedrum","snare","hat","bass","flute","bell","guitar","chime","xylophone","iron_xylophone","cow_bell","didgeridoo","bit","banjo","pling"],"type":"enum"},"note":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24"],"type":"int"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:note_block[instrument=harp,note=0,powered=false]"},"minecraft:oak_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_button[face=wall,facing=north,powered=false]"},"minecraft:oak_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:oak_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:oak_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:oak_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_leaves[distance=7,persistent=false]"},"minecraft:oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:oak_log[axis=y]"},"minecraft:oak_planks":{"properties":{},"defaultstate":"minecraft:oak_planks"},"minecraft:oak_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_pressure_plate[powered=false]"},"minecraft:oak_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:oak_sapling[stage=0]"},"minecraft:oak_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_sign[rotation=0,waterlogged=false]"},"minecraft:oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_slab[type=bottom,waterlogged=false]"},"minecraft:oak_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:oak_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:oak_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_wall_sign[facing=north,waterlogged=false]"},"minecraft:oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:oak_wood[axis=y]"},"minecraft:observer":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:observer[facing=south,powered=false]"},"minecraft:obsidian":{"properties":{},"defaultstate":"minecraft:obsidian"},"minecraft:orange_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:orange_banner[rotation=0]"},"minecraft:orange_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:orange_bed[facing=north,occupied=false,part=foot]"},"minecraft:orange_carpet":{"properties":{},"defaultstate":"minecraft:orange_carpet"},"minecraft:orange_concrete":{"properties":{},"defaultstate":"minecraft:orange_concrete"},"minecraft:orange_concrete_powder":{"properties":{},"defaultstate":"minecraft:orange_concrete_powder"},"minecraft:orange_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:orange_glazed_terracotta[facing=north]"},"minecraft:orange_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:orange_shulker_box[facing=up]"},"minecraft:orange_stained_glass":{"properties":{},"defaultstate":"minecraft:orange_stained_glass"},"minecraft:orange_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:orange_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:orange_terracotta":{"properties":{},"defaultstate":"minecraft:orange_terracotta"},"minecraft:orange_tulip":{"properties":{},"defaultstate":"minecraft:orange_tulip"},"minecraft:orange_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:orange_wall_banner[facing=north]"},"minecraft:orange_wool":{"properties":{},"defaultstate":"minecraft:orange_wool"},"minecraft:oxeye_daisy":{"properties":{},"defaultstate":"minecraft:oxeye_daisy"},"minecraft:packed_ice":{"properties":{},"defaultstate":"minecraft:packed_ice"},"minecraft:peony":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:peony[half=lower]"},"minecraft:petrified_oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:petrified_oak_slab[type=bottom,waterlogged=false]"},"minecraft:pink_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:pink_banner[rotation=0]"},"minecraft:pink_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:pink_bed[facing=north,occupied=false,part=foot]"},"minecraft:pink_carpet":{"properties":{},"defaultstate":"minecraft:pink_carpet"},"minecraft:pink_concrete":{"properties":{},"defaultstate":"minecraft:pink_concrete"},"minecraft:pink_concrete_powder":{"properties":{},"defaultstate":"minecraft:pink_concrete_powder"},"minecraft:pink_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:pink_glazed_terracotta[facing=north]"},"minecraft:pink_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:pink_shulker_box[facing=up]"},"minecraft:pink_stained_glass":{"properties":{},"defaultstate":"minecraft:pink_stained_glass"},"minecraft:pink_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:pink_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:pink_terracotta":{"properties":{},"defaultstate":"minecraft:pink_terracotta"},"minecraft:pink_tulip":{"properties":{},"defaultstate":"minecraft:pink_tulip"},"minecraft:pink_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:pink_wall_banner[facing=north]"},"minecraft:pink_wool":{"properties":{},"defaultstate":"minecraft:pink_wool"},"minecraft:piston":{"properties":{"extended":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:piston[extended=false,facing=north]"},"minecraft:piston_head":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"short":{"values":["true","false"],"type":"bool"},"type":{"values":["normal","sticky"],"type":"enum"}},"defaultstate":"minecraft:piston_head[facing=north,short=false,type=normal]"},"minecraft:player_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:player_head[rotation=0]"},"minecraft:player_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:player_wall_head[facing=north]"},"minecraft:podzol":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:podzol[snowy=false]"},"minecraft:polished_andesite":{"properties":{},"defaultstate":"minecraft:polished_andesite"},"minecraft:polished_andesite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_andesite_slab[type=bottom,waterlogged=false]"},"minecraft:polished_andesite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_andesite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:polished_diorite":{"properties":{},"defaultstate":"minecraft:polished_diorite"},"minecraft:polished_diorite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_diorite_slab[type=bottom,waterlogged=false]"},"minecraft:polished_diorite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_diorite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:polished_granite":{"properties":{},"defaultstate":"minecraft:polished_granite"},"minecraft:polished_granite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_granite_slab[type=bottom,waterlogged=false]"},"minecraft:polished_granite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_granite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:poppy":{"properties":{},"defaultstate":"minecraft:poppy"},"minecraft:potatoes":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:potatoes[age=0]"},"minecraft:potted_acacia_sapling":{"properties":{},"defaultstate":"minecraft:potted_acacia_sapling"},"minecraft:potted_allium":{"properties":{},"defaultstate":"minecraft:potted_allium"},"minecraft:potted_azure_bluet":{"properties":{},"defaultstate":"minecraft:potted_azure_bluet"},"minecraft:potted_bamboo":{"properties":{},"defaultstate":"minecraft:potted_bamboo"},"minecraft:potted_birch_sapling":{"properties":{},"defaultstate":"minecraft:potted_birch_sapling"},"minecraft:potted_blue_orchid":{"properties":{},"defaultstate":"minecraft:potted_blue_orchid"},"minecraft:potted_brown_mushroom":{"properties":{},"defaultstate":"minecraft:potted_brown_mushroom"},"minecraft:potted_cactus":{"properties":{},"defaultstate":"minecraft:potted_cactus"},"minecraft:potted_cornflower":{"properties":{},"defaultstate":"minecraft:potted_cornflower"},"minecraft:potted_dandelion":{"properties":{},"defaultstate":"minecraft:potted_dandelion"},"minecraft:potted_dark_oak_sapling":{"properties":{},"defaultstate":"minecraft:potted_dark_oak_sapling"},"minecraft:potted_dead_bush":{"properties":{},"defaultstate":"minecraft:potted_dead_bush"},"minecraft:potted_fern":{"properties":{},"defaultstate":"minecraft:potted_fern"},"minecraft:potted_jungle_sapling":{"properties":{},"defaultstate":"minecraft:potted_jungle_sapling"},"minecraft:potted_lily_of_the_valley":{"properties":{},"defaultstate":"minecraft:potted_lily_of_the_valley"},"minecraft:potted_oak_sapling":{"properties":{},"defaultstate":"minecraft:potted_oak_sapling"},"minecraft:potted_orange_tulip":{"properties":{},"defaultstate":"minecraft:potted_orange_tulip"},"minecraft:potted_oxeye_daisy":{"properties":{},"defaultstate":"minecraft:potted_oxeye_daisy"},"minecraft:potted_pink_tulip":{"properties":{},"defaultstate":"minecraft:potted_pink_tulip"},"minecraft:potted_poppy":{"properties":{},"defaultstate":"minecraft:potted_poppy"},"minecraft:potted_red_mushroom":{"properties":{},"defaultstate":"minecraft:potted_red_mushroom"},"minecraft:potted_red_tulip":{"properties":{},"defaultstate":"minecraft:potted_red_tulip"},"minecraft:potted_spruce_sapling":{"properties":{},"defaultstate":"minecraft:potted_spruce_sapling"},"minecraft:potted_white_tulip":{"properties":{},"defaultstate":"minecraft:potted_white_tulip"},"minecraft:potted_wither_rose":{"properties":{},"defaultstate":"minecraft:potted_wither_rose"},"minecraft:powered_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:powered_rail[powered=false,shape=north_south]"},"minecraft:prismarine":{"properties":{},"defaultstate":"minecraft:prismarine"},"minecraft:prismarine_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_brick_slab[type=bottom,waterlogged=false]"},"minecraft:prismarine_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:prismarine_bricks":{"properties":{},"defaultstate":"minecraft:prismarine_bricks"},"minecraft:prismarine_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_slab[type=bottom,waterlogged=false]"},"minecraft:prismarine_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:prismarine_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:pumpkin":{"properties":{},"defaultstate":"minecraft:pumpkin"},"minecraft:pumpkin_stem":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:pumpkin_stem[age=0]"},"minecraft:purple_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:purple_banner[rotation=0]"},"minecraft:purple_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:purple_bed[facing=north,occupied=false,part=foot]"},"minecraft:purple_carpet":{"properties":{},"defaultstate":"minecraft:purple_carpet"},"minecraft:purple_concrete":{"properties":{},"defaultstate":"minecraft:purple_concrete"},"minecraft:purple_concrete_powder":{"properties":{},"defaultstate":"minecraft:purple_concrete_powder"},"minecraft:purple_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:purple_glazed_terracotta[facing=north]"},"minecraft:purple_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:purple_shulker_box[facing=up]"},"minecraft:purple_stained_glass":{"properties":{},"defaultstate":"minecraft:purple_stained_glass"},"minecraft:purple_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purple_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:purple_terracotta":{"properties":{},"defaultstate":"minecraft:purple_terracotta"},"minecraft:purple_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:purple_wall_banner[facing=north]"},"minecraft:purple_wool":{"properties":{},"defaultstate":"minecraft:purple_wool"},"minecraft:purpur_block":{"properties":{},"defaultstate":"minecraft:purpur_block"},"minecraft:purpur_pillar":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:purpur_pillar[axis=y]"},"minecraft:purpur_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purpur_slab[type=bottom,waterlogged=false]"},"minecraft:purpur_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purpur_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:quartz_block":{"properties":{},"defaultstate":"minecraft:quartz_block"},"minecraft:quartz_pillar":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:quartz_pillar[axis=y]"},"minecraft:quartz_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:quartz_slab[type=bottom,waterlogged=false]"},"minecraft:quartz_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:quartz_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:rail":{"properties":{"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south","south_east","south_west","north_west","north_east"],"type":"enum"}},"defaultstate":"minecraft:rail[shape=north_south]"},"minecraft:red_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:red_banner[rotation=0]"},"minecraft:red_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:red_bed[facing=north,occupied=false,part=foot]"},"minecraft:red_carpet":{"properties":{},"defaultstate":"minecraft:red_carpet"},"minecraft:red_concrete":{"properties":{},"defaultstate":"minecraft:red_concrete"},"minecraft:red_concrete_powder":{"properties":{},"defaultstate":"minecraft:red_concrete_powder"},"minecraft:red_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:red_glazed_terracotta[facing=north]"},"minecraft:red_mushroom":{"properties":{},"defaultstate":"minecraft:red_mushroom"},"minecraft:red_mushroom_block":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:red_nether_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_nether_brick_slab[type=bottom,waterlogged=false]"},"minecraft:red_nether_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_nether_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:red_nether_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_nether_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:red_nether_bricks":{"properties":{},"defaultstate":"minecraft:red_nether_bricks"},"minecraft:red_sand":{"properties":{},"defaultstate":"minecraft:red_sand"},"minecraft:red_sandstone":{"properties":{},"defaultstate":"minecraft:red_sandstone"},"minecraft:red_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:red_sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:red_sandstone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:red_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:red_shulker_box[facing=up]"},"minecraft:red_stained_glass":{"properties":{},"defaultstate":"minecraft:red_stained_glass"},"minecraft:red_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:red_terracotta":{"properties":{},"defaultstate":"minecraft:red_terracotta"},"minecraft:red_tulip":{"properties":{},"defaultstate":"minecraft:red_tulip"},"minecraft:red_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:red_wall_banner[facing=north]"},"minecraft:red_wool":{"properties":{},"defaultstate":"minecraft:red_wool"},"minecraft:redstone_block":{"properties":{},"defaultstate":"minecraft:redstone_block"},"minecraft:redstone_lamp":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_lamp[lit=false]"},"minecraft:redstone_ore":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_ore[lit=false]"},"minecraft:redstone_torch":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_torch[lit=true]"},"minecraft:redstone_wall_torch":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_wall_torch[facing=north,lit=true]"},"minecraft:redstone_wire":{"properties":{"east":{"values":["up","side","none"],"type":"enum"},"north":{"values":["up","side","none"],"type":"enum"},"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"south":{"values":["up","side","none"],"type":"enum"},"west":{"values":["up","side","none"],"type":"enum"}},"defaultstate":"minecraft:redstone_wire[east=none,north=none,power=0,south=none,west=none]"},"minecraft:repeater":{"properties":{"delay":{"values":["1","2","3","4"],"type":"int"},"facing":{"values":["north","south","west","east"],"type":"direction"},"locked":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:repeater[delay=1,facing=north,locked=false,powered=false]"},"minecraft:repeating_command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:repeating_command_block[conditional=false,facing=north]"},"minecraft:rose_bush":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:rose_bush[half=lower]"},"minecraft:sand":{"properties":{},"defaultstate":"minecraft:sand"},"minecraft:sandstone":{"properties":{},"defaultstate":"minecraft:sandstone"},"minecraft:sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:sandstone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:scaffolding":{"properties":{"bottom":{"values":["true","false"],"type":"bool"},"distance":{"values":["0","1","2","3","4","5","6","7"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:scaffolding[bottom=false,distance=7,waterlogged=false]"},"minecraft:sea_lantern":{"properties":{},"defaultstate":"minecraft:sea_lantern"},"minecraft:sea_pickle":{"properties":{"pickles":{"values":["1","2","3","4"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sea_pickle[pickles=1,waterlogged=true]"},"minecraft:seagrass":{"properties":{},"defaultstate":"minecraft:seagrass"},"minecraft:shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:shulker_box[facing=up]"},"minecraft:skeleton_skull":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:skeleton_skull[rotation=0]"},"minecraft:skeleton_wall_skull":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:skeleton_wall_skull[facing=north]"},"minecraft:slime_block":{"properties":{},"defaultstate":"minecraft:slime_block"},"minecraft:smithing_table":{"properties":{},"defaultstate":"minecraft:smithing_table"},"minecraft:smoker":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smoker[facing=north,lit=false]"},"minecraft:smooth_quartz":{"properties":{},"defaultstate":"minecraft:smooth_quartz"},"minecraft:smooth_quartz_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_quartz_slab[type=bottom,waterlogged=false]"},"minecraft:smooth_quartz_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_quartz_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:smooth_red_sandstone":{"properties":{},"defaultstate":"minecraft:smooth_red_sandstone"},"minecraft:smooth_red_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_red_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:smooth_red_sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_red_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:smooth_sandstone":{"properties":{},"defaultstate":"minecraft:smooth_sandstone"},"minecraft:smooth_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:smooth_sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:smooth_stone":{"properties":{},"defaultstate":"minecraft:smooth_stone"},"minecraft:smooth_stone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_stone_slab[type=bottom,waterlogged=false]"},"minecraft:snow":{"properties":{"layers":{"values":["1","2","3","4","5","6","7","8"],"type":"int"}},"defaultstate":"minecraft:snow[layers=1]"},"minecraft:snow_block":{"properties":{},"defaultstate":"minecraft:snow_block"},"minecraft:soul_sand":{"properties":{},"defaultstate":"minecraft:soul_sand"},"minecraft:spawner":{"properties":{},"defaultstate":"minecraft:spawner"},"minecraft:sponge":{"properties":{},"defaultstate":"minecraft:sponge"},"minecraft:spruce_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_button[face=wall,facing=north,powered=false]"},"minecraft:spruce_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:spruce_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:spruce_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:spruce_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_leaves[distance=7,persistent=false]"},"minecraft:spruce_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:spruce_log[axis=y]"},"minecraft:spruce_planks":{"properties":{},"defaultstate":"minecraft:spruce_planks"},"minecraft:spruce_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_pressure_plate[powered=false]"},"minecraft:spruce_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:spruce_sapling[stage=0]"},"minecraft:spruce_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_sign[rotation=0,waterlogged=false]"},"minecraft:spruce_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_slab[type=bottom,waterlogged=false]"},"minecraft:spruce_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:spruce_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:spruce_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_wall_sign[facing=north,waterlogged=false]"},"minecraft:spruce_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:spruce_wood[axis=y]"},"minecraft:sticky_piston":{"properties":{"extended":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:sticky_piston[extended=false,facing=north]"},"minecraft:stone":{"properties":{},"defaultstate":"minecraft:stone"},"minecraft:stone_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_slab[type=bottom,waterlogged=false]"},"minecraft:stone_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:stone_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:stone_bricks":{"properties":{},"defaultstate":"minecraft:stone_bricks"},"minecraft:stone_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_button[face=wall,facing=north,powered=false]"},"minecraft:stone_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_pressure_plate[powered=false]"},"minecraft:stone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_slab[type=bottom,waterlogged=false]"},"minecraft:stone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:stonecutter":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:stonecutter[facing=north]"},"minecraft:stripped_acacia_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_acacia_log[axis=y]"},"minecraft:stripped_acacia_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_acacia_wood[axis=y]"},"minecraft:stripped_birch_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_birch_log[axis=y]"},"minecraft:stripped_birch_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_birch_wood[axis=y]"},"minecraft:stripped_dark_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_dark_oak_log[axis=y]"},"minecraft:stripped_dark_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_dark_oak_wood[axis=y]"},"minecraft:stripped_jungle_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_jungle_log[axis=y]"},"minecraft:stripped_jungle_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_jungle_wood[axis=y]"},"minecraft:stripped_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_oak_log[axis=y]"},"minecraft:stripped_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_oak_wood[axis=y]"},"minecraft:stripped_spruce_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_spruce_log[axis=y]"},"minecraft:stripped_spruce_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_spruce_wood[axis=y]"},"minecraft:structure_block":{"properties":{"mode":{"values":["save","load","corner","data"],"type":"enum"}},"defaultstate":"minecraft:structure_block[mode=save]"},"minecraft:structure_void":{"properties":{},"defaultstate":"minecraft:structure_void"},"minecraft:sugar_cane":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:sugar_cane[age=0]"},"minecraft:sunflower":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:sunflower[half=lower]"},"minecraft:sweet_berry_bush":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:sweet_berry_bush[age=0]"},"minecraft:tall_grass":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:tall_grass[half=lower]"},"minecraft:tall_seagrass":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:tall_seagrass[half=lower]"},"minecraft:terracotta":{"properties":{},"defaultstate":"minecraft:terracotta"},"minecraft:tnt":{"properties":{"unstable":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tnt[unstable=false]"},"minecraft:torch":{"properties":{},"defaultstate":"minecraft:torch"},"minecraft:trapped_chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"type":{"values":["single","left","right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:trapped_chest[facing=north,type=single,waterlogged=false]"},"minecraft:tripwire":{"properties":{"attached":{"values":["true","false"],"type":"bool"},"disarmed":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,powered=false,south=false,west=false]"},"minecraft:tripwire_hook":{"properties":{"attached":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tripwire_hook[attached=false,facing=north,powered=false]"},"minecraft:tube_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral[waterlogged=true]"},"minecraft:tube_coral_block":{"properties":{},"defaultstate":"minecraft:tube_coral_block"},"minecraft:tube_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral_fan[waterlogged=true]"},"minecraft:tube_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:turtle_egg":{"properties":{"eggs":{"values":["1","2","3","4"],"type":"int"},"hatch":{"values":["0","1","2"],"type":"int"}},"defaultstate":"minecraft:turtle_egg[eggs=1,hatch=0]"},"minecraft:vine":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:vine[east=false,north=false,south=false,up=false,west=false]"},"minecraft:void_air":{"properties":{},"defaultstate":"minecraft:void_air"},"minecraft:wall_torch":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:wall_torch[facing=north]"},"minecraft:water":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:water[level=0]"},"minecraft:wet_sponge":{"properties":{},"defaultstate":"minecraft:wet_sponge"},"minecraft:wheat":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:wheat[age=0]"},"minecraft:white_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:white_banner[rotation=0]"},"minecraft:white_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:white_bed[facing=north,occupied=false,part=foot]"},"minecraft:white_carpet":{"properties":{},"defaultstate":"minecraft:white_carpet"},"minecraft:white_concrete":{"properties":{},"defaultstate":"minecraft:white_concrete"},"minecraft:white_concrete_powder":{"properties":{},"defaultstate":"minecraft:white_concrete_powder"},"minecraft:white_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:white_glazed_terracotta[facing=north]"},"minecraft:white_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:white_shulker_box[facing=up]"},"minecraft:white_stained_glass":{"properties":{},"defaultstate":"minecraft:white_stained_glass"},"minecraft:white_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:white_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:white_terracotta":{"properties":{},"defaultstate":"minecraft:white_terracotta"},"minecraft:white_tulip":{"properties":{},"defaultstate":"minecraft:white_tulip"},"minecraft:white_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:white_wall_banner[facing=north]"},"minecraft:white_wool":{"properties":{},"defaultstate":"minecraft:white_wool"},"minecraft:wither_rose":{"properties":{},"defaultstate":"minecraft:wither_rose"},"minecraft:wither_skeleton_skull":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:wither_skeleton_skull[rotation=0]"},"minecraft:wither_skeleton_wall_skull":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:wither_skeleton_wall_skull[facing=north]"},"minecraft:yellow_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:yellow_banner[rotation=0]"},"minecraft:yellow_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:yellow_bed[facing=north,occupied=false,part=foot]"},"minecraft:yellow_carpet":{"properties":{},"defaultstate":"minecraft:yellow_carpet"},"minecraft:yellow_concrete":{"properties":{},"defaultstate":"minecraft:yellow_concrete"},"minecraft:yellow_concrete_powder":{"properties":{},"defaultstate":"minecraft:yellow_concrete_powder"},"minecraft:yellow_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:yellow_glazed_terracotta[facing=north]"},"minecraft:yellow_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:yellow_shulker_box[facing=up]"},"minecraft:yellow_stained_glass":{"properties":{},"defaultstate":"minecraft:yellow_stained_glass"},"minecraft:yellow_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:yellow_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:yellow_terracotta":{"properties":{},"defaultstate":"minecraft:yellow_terracotta"},"minecraft:yellow_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:yellow_wall_banner[facing=north]"},"minecraft:yellow_wool":{"properties":{},"defaultstate":"minecraft:yellow_wool"},"minecraft:zombie_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:zombie_head[rotation=0]"},"minecraft:zombie_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:zombie_wall_head[facing=north]"}},"items":["minecraft:acacia_boat","minecraft:acacia_button","minecraft:acacia_door","minecraft:acacia_fence","minecraft:acacia_fence_gate","minecraft:acacia_leaves","minecraft:acacia_log","minecraft:acacia_planks","minecraft:acacia_pressure_plate","minecraft:acacia_sapling","minecraft:acacia_sign","minecraft:acacia_slab","minecraft:acacia_stairs","minecraft:acacia_trapdoor","minecraft:acacia_wood","minecraft:activator_rail","minecraft:air","minecraft:allium","minecraft:andesite","minecraft:andesite_slab","minecraft:andesite_stairs","minecraft:andesite_wall","minecraft:anvil","minecraft:apple","minecraft:armor_stand","minecraft:arrow","minecraft:azure_bluet","minecraft:baked_potato","minecraft:bamboo","minecraft:barrel","minecraft:barrier","minecraft:bat_spawn_egg","minecraft:beacon","minecraft:bedrock","minecraft:beef","minecraft:beetroot","minecraft:beetroot_seeds","minecraft:beetroot_soup","minecraft:bell","minecraft:birch_boat","minecraft:birch_button","minecraft:birch_door","minecraft:birch_fence","minecraft:birch_fence_gate","minecraft:birch_leaves","minecraft:birch_log","minecraft:birch_planks","minecraft:birch_pressure_plate","minecraft:birch_sapling","minecraft:birch_sign","minecraft:birch_slab","minecraft:birch_stairs","minecraft:birch_trapdoor","minecraft:birch_wood","minecraft:black_banner","minecraft:black_bed","minecraft:black_carpet","minecraft:black_concrete","minecraft:black_concrete_powder","minecraft:black_dye","minecraft:black_glazed_terracotta","minecraft:black_shulker_box","minecraft:black_stained_glass","minecraft:black_stained_glass_pane","minecraft:black_terracotta","minecraft:black_wool","minecraft:blast_furnace","minecraft:blaze_powder","minecraft:blaze_rod","minecraft:blaze_spawn_egg","minecraft:blue_banner","minecraft:blue_bed","minecraft:blue_carpet","minecraft:blue_concrete","minecraft:blue_concrete_powder","minecraft:blue_dye","minecraft:blue_glazed_terracotta","minecraft:blue_ice","minecraft:blue_orchid","minecraft:blue_shulker_box","minecraft:blue_stained_glass","minecraft:blue_stained_glass_pane","minecraft:blue_terracotta","minecraft:blue_wool","minecraft:bone","minecraft:bone_block","minecraft:bone_meal","minecraft:book","minecraft:bookshelf","minecraft:bow","minecraft:bowl","minecraft:brain_coral","minecraft:brain_coral_block","minecraft:brain_coral_fan","minecraft:bread","minecraft:brewing_stand","minecraft:brick","minecraft:brick_slab","minecraft:brick_stairs","minecraft:brick_wall","minecraft:bricks","minecraft:brown_banner","minecraft:brown_bed","minecraft:brown_carpet","minecraft:brown_concrete","minecraft:brown_concrete_powder","minecraft:brown_dye","minecraft:brown_glazed_terracotta","minecraft:brown_mushroom","minecraft:brown_mushroom_block","minecraft:brown_shulker_box","minecraft:brown_stained_glass","minecraft:brown_stained_glass_pane","minecraft:brown_terracotta","minecraft:brown_wool","minecraft:bubble_coral","minecraft:bubble_coral_block","minecraft:bubble_coral_fan","minecraft:bucket","minecraft:cactus","minecraft:cake","minecraft:campfire","minecraft:carrot","minecraft:carrot_on_a_stick","minecraft:cartography_table","minecraft:carved_pumpkin","minecraft:cat_spawn_egg","minecraft:cauldron","minecraft:cave_spider_spawn_egg","minecraft:chain_command_block","minecraft:chainmail_boots","minecraft:chainmail_chestplate","minecraft:chainmail_helmet","minecraft:chainmail_leggings","minecraft:charcoal","minecraft:chest","minecraft:chest_minecart","minecraft:chicken","minecraft:chicken_spawn_egg","minecraft:chipped_anvil","minecraft:chiseled_quartz_block","minecraft:chiseled_red_sandstone","minecraft:chiseled_sandstone","minecraft:chiseled_stone_bricks","minecraft:chorus_flower","minecraft:chorus_fruit","minecraft:chorus_plant","minecraft:clay","minecraft:clay_ball","minecraft:clock","minecraft:coal","minecraft:coal_block","minecraft:coal_ore","minecraft:coarse_dirt","minecraft:cobblestone","minecraft:cobblestone_slab","minecraft:cobblestone_stairs","minecraft:cobblestone_wall","minecraft:cobweb","minecraft:cocoa_beans","minecraft:cod","minecraft:cod_bucket","minecraft:cod_spawn_egg","minecraft:command_block","minecraft:command_block_minecart","minecraft:comparator","minecraft:compass","minecraft:composter","minecraft:conduit","minecraft:cooked_beef","minecraft:cooked_chicken","minecraft:cooked_cod","minecraft:cooked_mutton","minecraft:cooked_porkchop","minecraft:cooked_rabbit","minecraft:cooked_salmon","minecraft:cookie","minecraft:cornflower","minecraft:cow_spawn_egg","minecraft:cracked_stone_bricks","minecraft:crafting_table","minecraft:creeper_banner_pattern","minecraft:creeper_head","minecraft:creeper_spawn_egg","minecraft:crossbow","minecraft:cut_red_sandstone","minecraft:cut_red_sandstone_slab","minecraft:cut_sandstone","minecraft:cut_sandstone_slab","minecraft:cyan_banner","minecraft:cyan_bed","minecraft:cyan_carpet","minecraft:cyan_concrete","minecraft:cyan_concrete_powder","minecraft:cyan_dye","minecraft:cyan_glazed_terracotta","minecraft:cyan_shulker_box","minecraft:cyan_stained_glass","minecraft:cyan_stained_glass_pane","minecraft:cyan_terracotta","minecraft:cyan_wool","minecraft:damaged_anvil","minecraft:dandelion","minecraft:dark_oak_boat","minecraft:dark_oak_button","minecraft:dark_oak_door","minecraft:dark_oak_fence","minecraft:dark_oak_fence_gate","minecraft:dark_oak_leaves","minecraft:dark_oak_log","minecraft:dark_oak_planks","minecraft:dark_oak_pressure_plate","minecraft:dark_oak_sapling","minecraft:dark_oak_sign","minecraft:dark_oak_slab","minecraft:dark_oak_stairs","minecraft:dark_oak_trapdoor","minecraft:dark_oak_wood","minecraft:dark_prismarine","minecraft:dark_prismarine_slab","minecraft:dark_prismarine_stairs","minecraft:daylight_detector","minecraft:dead_brain_coral","minecraft:dead_brain_coral_block","minecraft:dead_brain_coral_fan","minecraft:dead_bubble_coral","minecraft:dead_bubble_coral_block","minecraft:dead_bubble_coral_fan","minecraft:dead_bush","minecraft:dead_fire_coral","minecraft:dead_fire_coral_block","minecraft:dead_fire_coral_fan","minecraft:dead_horn_coral","minecraft:dead_horn_coral_block","minecraft:dead_horn_coral_fan","minecraft:dead_tube_coral","minecraft:dead_tube_coral_block","minecraft:dead_tube_coral_fan","minecraft:debug_stick","minecraft:detector_rail","minecraft:diamond","minecraft:diamond_axe","minecraft:diamond_block","minecraft:diamond_boots","minecraft:diamond_chestplate","minecraft:diamond_helmet","minecraft:diamond_hoe","minecraft:diamond_horse_armor","minecraft:diamond_leggings","minecraft:diamond_ore","minecraft:diamond_pickaxe","minecraft:diamond_shovel","minecraft:diamond_sword","minecraft:diorite","minecraft:diorite_slab","minecraft:diorite_stairs","minecraft:diorite_wall","minecraft:dirt","minecraft:dispenser","minecraft:dolphin_spawn_egg","minecraft:donkey_spawn_egg","minecraft:dragon_breath","minecraft:dragon_egg","minecraft:dragon_head","minecraft:dried_kelp","minecraft:dried_kelp_block","minecraft:dropper","minecraft:drowned_spawn_egg","minecraft:egg","minecraft:elder_guardian_spawn_egg","minecraft:elytra","minecraft:emerald","minecraft:emerald_block","minecraft:emerald_ore","minecraft:enchanted_book","minecraft:enchanted_golden_apple","minecraft:enchanting_table","minecraft:end_crystal","minecraft:end_portal_frame","minecraft:end_rod","minecraft:end_stone","minecraft:end_stone_brick_slab","minecraft:end_stone_brick_stairs","minecraft:end_stone_brick_wall","minecraft:end_stone_bricks","minecraft:ender_chest","minecraft:ender_eye","minecraft:ender_pearl","minecraft:enderman_spawn_egg","minecraft:endermite_spawn_egg","minecraft:evoker_spawn_egg","minecraft:experience_bottle","minecraft:farmland","minecraft:feather","minecraft:fermented_spider_eye","minecraft:fern","minecraft:filled_map","minecraft:fire_charge","minecraft:fire_coral","minecraft:fire_coral_block","minecraft:fire_coral_fan","minecraft:firework_rocket","minecraft:firework_star","minecraft:fishing_rod","minecraft:fletching_table","minecraft:flint","minecraft:flint_and_steel","minecraft:flower_banner_pattern","minecraft:flower_pot","minecraft:fox_spawn_egg","minecraft:furnace","minecraft:furnace_minecart","minecraft:ghast_spawn_egg","minecraft:ghast_tear","minecraft:glass","minecraft:glass_bottle","minecraft:glass_pane","minecraft:glistering_melon_slice","minecraft:globe_banner_pattern","minecraft:glowstone","minecraft:glowstone_dust","minecraft:gold_block","minecraft:gold_ingot","minecraft:gold_nugget","minecraft:gold_ore","minecraft:golden_apple","minecraft:golden_axe","minecraft:golden_boots","minecraft:golden_carrot","minecraft:golden_chestplate","minecraft:golden_helmet","minecraft:golden_hoe","minecraft:golden_horse_armor","minecraft:golden_leggings","minecraft:golden_pickaxe","minecraft:golden_shovel","minecraft:golden_sword","minecraft:granite","minecraft:granite_slab","minecraft:granite_stairs","minecraft:granite_wall","minecraft:grass","minecraft:grass_block","minecraft:grass_path","minecraft:gravel","minecraft:gray_banner","minecraft:gray_bed","minecraft:gray_carpet","minecraft:gray_concrete","minecraft:gray_concrete_powder","minecraft:gray_dye","minecraft:gray_glazed_terracotta","minecraft:gray_shulker_box","minecraft:gray_stained_glass","minecraft:gray_stained_glass_pane","minecraft:gray_terracotta","minecraft:gray_wool","minecraft:green_banner","minecraft:green_bed","minecraft:green_carpet","minecraft:green_concrete","minecraft:green_concrete_powder","minecraft:green_dye","minecraft:green_glazed_terracotta","minecraft:green_shulker_box","minecraft:green_stained_glass","minecraft:green_stained_glass_pane","minecraft:green_terracotta","minecraft:green_wool","minecraft:grindstone","minecraft:guardian_spawn_egg","minecraft:gunpowder","minecraft:hay_block","minecraft:heart_of_the_sea","minecraft:heavy_weighted_pressure_plate","minecraft:hopper","minecraft:hopper_minecart","minecraft:horn_coral","minecraft:horn_coral_block","minecraft:horn_coral_fan","minecraft:horse_spawn_egg","minecraft:husk_spawn_egg","minecraft:ice","minecraft:infested_chiseled_stone_bricks","minecraft:infested_cobblestone","minecraft:infested_cracked_stone_bricks","minecraft:infested_mossy_stone_bricks","minecraft:infested_stone","minecraft:infested_stone_bricks","minecraft:ink_sac","minecraft:iron_axe","minecraft:iron_bars","minecraft:iron_block","minecraft:iron_boots","minecraft:iron_chestplate","minecraft:iron_door","minecraft:iron_helmet","minecraft:iron_hoe","minecraft:iron_horse_armor","minecraft:iron_ingot","minecraft:iron_leggings","minecraft:iron_nugget","minecraft:iron_ore","minecraft:iron_pickaxe","minecraft:iron_shovel","minecraft:iron_sword","minecraft:iron_trapdoor","minecraft:item_frame","minecraft:jack_o_lantern","minecraft:jigsaw","minecraft:jukebox","minecraft:jungle_boat","minecraft:jungle_button","minecraft:jungle_door","minecraft:jungle_fence","minecraft:jungle_fence_gate","minecraft:jungle_leaves","minecraft:jungle_log","minecraft:jungle_planks","minecraft:jungle_pressure_plate","minecraft:jungle_sapling","minecraft:jungle_sign","minecraft:jungle_slab","minecraft:jungle_stairs","minecraft:jungle_trapdoor","minecraft:jungle_wood","minecraft:kelp","minecraft:knowledge_book","minecraft:ladder","minecraft:lantern","minecraft:lapis_block","minecraft:lapis_lazuli","minecraft:lapis_ore","minecraft:large_fern","minecraft:lava_bucket","minecraft:lead","minecraft:leather","minecraft:leather_boots","minecraft:leather_chestplate","minecraft:leather_helmet","minecraft:leather_horse_armor","minecraft:leather_leggings","minecraft:lectern","minecraft:lever","minecraft:light_blue_banner","minecraft:light_blue_bed","minecraft:light_blue_carpet","minecraft:light_blue_concrete","minecraft:light_blue_concrete_powder","minecraft:light_blue_dye","minecraft:light_blue_glazed_terracotta","minecraft:light_blue_shulker_box","minecraft:light_blue_stained_glass","minecraft:light_blue_stained_glass_pane","minecraft:light_blue_terracotta","minecraft:light_blue_wool","minecraft:light_gray_banner","minecraft:light_gray_bed","minecraft:light_gray_carpet","minecraft:light_gray_concrete","minecraft:light_gray_concrete_powder","minecraft:light_gray_dye","minecraft:light_gray_glazed_terracotta","minecraft:light_gray_shulker_box","minecraft:light_gray_stained_glass","minecraft:light_gray_stained_glass_pane","minecraft:light_gray_terracotta","minecraft:light_gray_wool","minecraft:light_weighted_pressure_plate","minecraft:lilac","minecraft:lily_of_the_valley","minecraft:lily_pad","minecraft:lime_banner","minecraft:lime_bed","minecraft:lime_carpet","minecraft:lime_concrete","minecraft:lime_concrete_powder","minecraft:lime_dye","minecraft:lime_glazed_terracotta","minecraft:lime_shulker_box","minecraft:lime_stained_glass","minecraft:lime_stained_glass_pane","minecraft:lime_terracotta","minecraft:lime_wool","minecraft:lingering_potion","minecraft:llama_spawn_egg","minecraft:loom","minecraft:magenta_banner","minecraft:magenta_bed","minecraft:magenta_carpet","minecraft:magenta_concrete","minecraft:magenta_concrete_powder","minecraft:magenta_dye","minecraft:magenta_glazed_terracotta","minecraft:magenta_shulker_box","minecraft:magenta_stained_glass","minecraft:magenta_stained_glass_pane","minecraft:magenta_terracotta","minecraft:magenta_wool","minecraft:magma_block","minecraft:magma_cream","minecraft:magma_cube_spawn_egg","minecraft:map","minecraft:melon","minecraft:melon_seeds","minecraft:melon_slice","minecraft:milk_bucket","minecraft:minecart","minecraft:mojang_banner_pattern","minecraft:mooshroom_spawn_egg","minecraft:mossy_cobblestone","minecraft:mossy_cobblestone_slab","minecraft:mossy_cobblestone_stairs","minecraft:mossy_cobblestone_wall","minecraft:mossy_stone_brick_slab","minecraft:mossy_stone_brick_stairs","minecraft:mossy_stone_brick_wall","minecraft:mossy_stone_bricks","minecraft:mule_spawn_egg","minecraft:mushroom_stem","minecraft:mushroom_stew","minecraft:music_disc_11","minecraft:music_disc_13","minecraft:music_disc_blocks","minecraft:music_disc_cat","minecraft:music_disc_chirp","minecraft:music_disc_far","minecraft:music_disc_mall","minecraft:music_disc_mellohi","minecraft:music_disc_stal","minecraft:music_disc_strad","minecraft:music_disc_wait","minecraft:music_disc_ward","minecraft:mutton","minecraft:mycelium","minecraft:name_tag","minecraft:nautilus_shell","minecraft:nether_brick","minecraft:nether_brick_fence","minecraft:nether_brick_slab","minecraft:nether_brick_stairs","minecraft:nether_brick_wall","minecraft:nether_bricks","minecraft:nether_quartz_ore","minecraft:nether_star","minecraft:nether_wart","minecraft:nether_wart_block","minecraft:netherrack","minecraft:note_block","minecraft:oak_boat","minecraft:oak_button","minecraft:oak_door","minecraft:oak_fence","minecraft:oak_fence_gate","minecraft:oak_leaves","minecraft:oak_log","minecraft:oak_planks","minecraft:oak_pressure_plate","minecraft:oak_sapling","minecraft:oak_sign","minecraft:oak_slab","minecraft:oak_stairs","minecraft:oak_trapdoor","minecraft:oak_wood","minecraft:observer","minecraft:obsidian","minecraft:ocelot_spawn_egg","minecraft:orange_banner","minecraft:orange_bed","minecraft:orange_carpet","minecraft:orange_concrete","minecraft:orange_concrete_powder","minecraft:orange_dye","minecraft:orange_glazed_terracotta","minecraft:orange_shulker_box","minecraft:orange_stained_glass","minecraft:orange_stained_glass_pane","minecraft:orange_terracotta","minecraft:orange_tulip","minecraft:orange_wool","minecraft:oxeye_daisy","minecraft:packed_ice","minecraft:painting","minecraft:panda_spawn_egg","minecraft:paper","minecraft:parrot_spawn_egg","minecraft:peony","minecraft:petrified_oak_slab","minecraft:phantom_membrane","minecraft:phantom_spawn_egg","minecraft:pig_spawn_egg","minecraft:pillager_spawn_egg","minecraft:pink_banner","minecraft:pink_bed","minecraft:pink_carpet","minecraft:pink_concrete","minecraft:pink_concrete_powder","minecraft:pink_dye","minecraft:pink_glazed_terracotta","minecraft:pink_shulker_box","minecraft:pink_stained_glass","minecraft:pink_stained_glass_pane","minecraft:pink_terracotta","minecraft:pink_tulip","minecraft:pink_wool","minecraft:piston","minecraft:player_head","minecraft:podzol","minecraft:poisonous_potato","minecraft:polar_bear_spawn_egg","minecraft:polished_andesite","minecraft:polished_andesite_slab","minecraft:polished_andesite_stairs","minecraft:polished_diorite","minecraft:polished_diorite_slab","minecraft:polished_diorite_stairs","minecraft:polished_granite","minecraft:polished_granite_slab","minecraft:polished_granite_stairs","minecraft:popped_chorus_fruit","minecraft:poppy","minecraft:porkchop","minecraft:potato","minecraft:potion","minecraft:powered_rail","minecraft:prismarine","minecraft:prismarine_brick_slab","minecraft:prismarine_brick_stairs","minecraft:prismarine_bricks","minecraft:prismarine_crystals","minecraft:prismarine_shard","minecraft:prismarine_slab","minecraft:prismarine_stairs","minecraft:prismarine_wall","minecraft:pufferfish","minecraft:pufferfish_bucket","minecraft:pufferfish_spawn_egg","minecraft:pumpkin","minecraft:pumpkin_pie","minecraft:pumpkin_seeds","minecraft:purple_banner","minecraft:purple_bed","minecraft:purple_carpet","minecraft:purple_concrete","minecraft:purple_concrete_powder","minecraft:purple_dye","minecraft:purple_glazed_terracotta","minecraft:purple_shulker_box","minecraft:purple_stained_glass","minecraft:purple_stained_glass_pane","minecraft:purple_terracotta","minecraft:purple_wool","minecraft:purpur_block","minecraft:purpur_pillar","minecraft:purpur_slab","minecraft:purpur_stairs","minecraft:quartz","minecraft:quartz_block","minecraft:quartz_pillar","minecraft:quartz_slab","minecraft:quartz_stairs","minecraft:rabbit","minecraft:rabbit_foot","minecraft:rabbit_hide","minecraft:rabbit_spawn_egg","minecraft:rabbit_stew","minecraft:rail","minecraft:ravager_spawn_egg","minecraft:red_banner","minecraft:red_bed","minecraft:red_carpet","minecraft:red_concrete","minecraft:red_concrete_powder","minecraft:red_dye","minecraft:red_glazed_terracotta","minecraft:red_mushroom","minecraft:red_mushroom_block","minecraft:red_nether_brick_slab","minecraft:red_nether_brick_stairs","minecraft:red_nether_brick_wall","minecraft:red_nether_bricks","minecraft:red_sand","minecraft:red_sandstone","minecraft:red_sandstone_slab","minecraft:red_sandstone_stairs","minecraft:red_sandstone_wall","minecraft:red_shulker_box","minecraft:red_stained_glass","minecraft:red_stained_glass_pane","minecraft:red_terracotta","minecraft:red_tulip","minecraft:red_wool","minecraft:redstone","minecraft:redstone_block","minecraft:redstone_lamp","minecraft:redstone_ore","minecraft:redstone_torch","minecraft:repeater","minecraft:repeating_command_block","minecraft:rose_bush","minecraft:rotten_flesh","minecraft:saddle","minecraft:salmon","minecraft:salmon_bucket","minecraft:salmon_spawn_egg","minecraft:sand","minecraft:sandstone","minecraft:sandstone_slab","minecraft:sandstone_stairs","minecraft:sandstone_wall","minecraft:scaffolding","minecraft:scute","minecraft:sea_lantern","minecraft:sea_pickle","minecraft:seagrass","minecraft:shears","minecraft:sheep_spawn_egg","minecraft:shield","minecraft:shulker_box","minecraft:shulker_shell","minecraft:shulker_spawn_egg","minecraft:silverfish_spawn_egg","minecraft:skeleton_horse_spawn_egg","minecraft:skeleton_skull","minecraft:skeleton_spawn_egg","minecraft:skull_banner_pattern","minecraft:slime_ball","minecraft:slime_block","minecraft:slime_spawn_egg","minecraft:smithing_table","minecraft:smoker","minecraft:smooth_quartz","minecraft:smooth_quartz_slab","minecraft:smooth_quartz_stairs","minecraft:smooth_red_sandstone","minecraft:smooth_red_sandstone_slab","minecraft:smooth_red_sandstone_stairs","minecraft:smooth_sandstone","minecraft:smooth_sandstone_slab","minecraft:smooth_sandstone_stairs","minecraft:smooth_stone","minecraft:smooth_stone_slab","minecraft:snow","minecraft:snow_block","minecraft:snowball","minecraft:soul_sand","minecraft:spawner","minecraft:spectral_arrow","minecraft:spider_eye","minecraft:spider_spawn_egg","minecraft:splash_potion","minecraft:sponge","minecraft:spruce_boat","minecraft:spruce_button","minecraft:spruce_door","minecraft:spruce_fence","minecraft:spruce_fence_gate","minecraft:spruce_leaves","minecraft:spruce_log","minecraft:spruce_planks","minecraft:spruce_pressure_plate","minecraft:spruce_sapling","minecraft:spruce_sign","minecraft:spruce_slab","minecraft:spruce_stairs","minecraft:spruce_trapdoor","minecraft:spruce_wood","minecraft:squid_spawn_egg","minecraft:stick","minecraft:sticky_piston","minecraft:stone","minecraft:stone_axe","minecraft:stone_brick_slab","minecraft:stone_brick_stairs","minecraft:stone_brick_wall","minecraft:stone_bricks","minecraft:stone_button","minecraft:stone_hoe","minecraft:stone_pickaxe","minecraft:stone_pressure_plate","minecraft:stone_shovel","minecraft:stone_slab","minecraft:stone_stairs","minecraft:stone_sword","minecraft:stonecutter","minecraft:stray_spawn_egg","minecraft:string","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood","minecraft:structure_block","minecraft:structure_void","minecraft:sugar","minecraft:sugar_cane","minecraft:sunflower","minecraft:suspicious_stew","minecraft:sweet_berries","minecraft:tall_grass","minecraft:terracotta","minecraft:tipped_arrow","minecraft:tnt","minecraft:tnt_minecart","minecraft:torch","minecraft:totem_of_undying","minecraft:trader_llama_spawn_egg","minecraft:trapped_chest","minecraft:trident","minecraft:tripwire_hook","minecraft:tropical_fish","minecraft:tropical_fish_bucket","minecraft:tropical_fish_spawn_egg","minecraft:tube_coral","minecraft:tube_coral_block","minecraft:tube_coral_fan","minecraft:turtle_egg","minecraft:turtle_helmet","minecraft:turtle_spawn_egg","minecraft:vex_spawn_egg","minecraft:villager_spawn_egg","minecraft:vindicator_spawn_egg","minecraft:vine","minecraft:wandering_trader_spawn_egg","minecraft:water_bucket","minecraft:wet_sponge","minecraft:wheat","minecraft:wheat_seeds","minecraft:white_banner","minecraft:white_bed","minecraft:white_carpet","minecraft:white_concrete","minecraft:white_concrete_powder","minecraft:white_dye","minecraft:white_glazed_terracotta","minecraft:white_shulker_box","minecraft:white_stained_glass","minecraft:white_stained_glass_pane","minecraft:white_terracotta","minecraft:white_tulip","minecraft:white_wool","minecraft:witch_spawn_egg","minecraft:wither_rose","minecraft:wither_skeleton_skull","minecraft:wither_skeleton_spawn_egg","minecraft:wolf_spawn_egg","minecraft:wooden_axe","minecraft:wooden_hoe","minecraft:wooden_pickaxe","minecraft:wooden_shovel","minecraft:wooden_sword","minecraft:writable_book","minecraft:written_book","minecraft:yellow_banner","minecraft:yellow_bed","minecraft:yellow_carpet","minecraft:yellow_concrete","minecraft:yellow_concrete_powder","minecraft:yellow_dye","minecraft:yellow_glazed_terracotta","minecraft:yellow_shulker_box","minecraft:yellow_stained_glass","minecraft:yellow_stained_glass_pane","minecraft:yellow_terracotta","minecraft:yellow_wool","minecraft:zombie_head","minecraft:zombie_horse_spawn_egg","minecraft:zombie_pigman_spawn_egg","minecraft:zombie_spawn_egg","minecraft:zombie_villager_spawn_egg"],"entities":["minecraft:area_effect_cloud","minecraft:armor_stand","minecraft:arrow","minecraft:bat","minecraft:blaze","minecraft:boat","minecraft:cat","minecraft:cave_spider","minecraft:chest_minecart","minecraft:chicken","minecraft:cod","minecraft:command_block_minecart","minecraft:cow","minecraft:creeper","minecraft:dolphin","minecraft:donkey","minecraft:dragon_fireball","minecraft:drowned","minecraft:egg","minecraft:elder_guardian","minecraft:end_crystal","minecraft:ender_dragon","minecraft:ender_pearl","minecraft:enderman","minecraft:endermite","minecraft:evoker","minecraft:evoker_fangs","minecraft:experience_bottle","minecraft:experience_orb","minecraft:eye_of_ender","minecraft:falling_block","minecraft:fireball","minecraft:firework_rocket","minecraft:fishing_bobber","minecraft:fox","minecraft:furnace_minecart","minecraft:ghast","minecraft:giant","minecraft:guardian","minecraft:hopper_minecart","minecraft:horse","minecraft:husk","minecraft:illusioner","minecraft:iron_golem","minecraft:item","minecraft:item_frame","minecraft:leash_knot","minecraft:lightning_bolt","minecraft:llama","minecraft:llama_spit","minecraft:magma_cube","minecraft:minecart","minecraft:mooshroom","minecraft:mule","minecraft:ocelot","minecraft:painting","minecraft:panda","minecraft:parrot","minecraft:phantom","minecraft:pig","minecraft:pillager","minecraft:player","minecraft:polar_bear","minecraft:potion","minecraft:pufferfish","minecraft:rabbit","minecraft:ravager","minecraft:salmon","minecraft:sheep","minecraft:shulker","minecraft:shulker_bullet","minecraft:silverfish","minecraft:skeleton","minecraft:skeleton_horse","minecraft:slime","minecraft:small_fireball","minecraft:snow_golem","minecraft:snowball","minecraft:spawner_minecart","minecraft:spectral_arrow","minecraft:spider","minecraft:squid","minecraft:stray","minecraft:tnt","minecraft:tnt_minecart","minecraft:trader_llama","minecraft:trident","minecraft:tropical_fish","minecraft:turtle","minecraft:vex","minecraft:villager","minecraft:vindicator","minecraft:wandering_trader","minecraft:witch","minecraft:wither","minecraft:wither_skeleton","minecraft:wither_skull","minecraft:wolf","minecraft:zombie","minecraft:zombie_horse","minecraft:zombie_pigman","minecraft:zombie_villager"],"biomes":["minecraft:badlands","minecraft:badlands_plateau","minecraft:bamboo_jungle","minecraft:bamboo_jungle_hills","minecraft:beach","minecraft:birch_forest","minecraft:birch_forest_hills","minecraft:cold_ocean","minecraft:dark_forest","minecraft:dark_forest_hills","minecraft:deep_cold_ocean","minecraft:deep_frozen_ocean","minecraft:deep_lukewarm_ocean","minecraft:deep_ocean","minecraft:deep_warm_ocean","minecraft:desert","minecraft:desert_hills","minecraft:desert_lakes","minecraft:end_barrens","minecraft:end_highlands","minecraft:end_midlands","minecraft:eroded_badlands","minecraft:flower_forest","minecraft:forest","minecraft:frozen_ocean","minecraft:frozen_river","minecraft:giant_spruce_taiga","minecraft:giant_spruce_taiga_hills","minecraft:giant_tree_taiga","minecraft:giant_tree_taiga_hills","minecraft:gravelly_mountains","minecraft:ice_spikes","minecraft:jungle","minecraft:jungle_edge","minecraft:jungle_hills","minecraft:lukewarm_ocean","minecraft:modified_badlands_plateau","minecraft:modified_gravelly_mountains","minecraft:modified_jungle","minecraft:modified_jungle_edge","minecraft:modified_wooded_badlands_plateau","minecraft:mountain_edge","minecraft:mountains","minecraft:mushroom_field_shore","minecraft:mushroom_fields","minecraft:nether","minecraft:ocean","minecraft:plains","minecraft:river","minecraft:savanna","minecraft:savanna_plateau","minecraft:shattered_savanna","minecraft:shattered_savanna_plateau","minecraft:small_end_islands","minecraft:snowy_beach","minecraft:snowy_mountains","minecraft:snowy_taiga","minecraft:snowy_taiga_hills","minecraft:snowy_taiga_mountains","minecraft:snowy_tundra","minecraft:stone_shore","minecraft:sunflower_plains","minecraft:swamp","minecraft:swamp_hills","minecraft:taiga","minecraft:taiga_hills","minecraft:taiga_mountains","minecraft:tall_birch_forest","minecraft:tall_birch_hills","minecraft:the_end","minecraft:the_void","minecraft:warm_ocean","minecraft:wooded_badlands_plateau","minecraft:wooded_hills","minecraft:wooded_mountains"],"blocktags":{"minecraft:slabs":["minecraft:stone_slab","minecraft:smooth_stone_slab","minecraft:stone_brick_slab","minecraft:sandstone_slab","minecraft:acacia_slab","minecraft:birch_slab","minecraft:dark_oak_slab","minecraft:jungle_slab","minecraft:oak_slab","minecraft:spruce_slab","minecraft:purpur_slab","minecraft:quartz_slab","minecraft:red_sandstone_slab","minecraft:brick_slab","minecraft:cobblestone_slab","minecraft:nether_brick_slab","minecraft:petrified_oak_slab","minecraft:prismarine_slab","minecraft:prismarine_brick_slab","minecraft:dark_prismarine_slab","minecraft:polished_granite_slab","minecraft:smooth_red_sandstone_slab","minecraft:mossy_stone_brick_slab","minecraft:polished_diorite_slab","minecraft:mossy_cobblestone_slab","minecraft:end_stone_brick_slab","minecraft:smooth_sandstone_slab","minecraft:smooth_quartz_slab","minecraft:granite_slab","minecraft:andesite_slab","minecraft:red_nether_brick_slab","minecraft:polished_andesite_slab","minecraft:diorite_slab","minecraft:cut_sandstone_slab","minecraft:cut_red_sandstone_slab"],"minecraft:carpets":["minecraft:white_carpet","minecraft:orange_carpet","minecraft:magenta_carpet","minecraft:light_blue_carpet","minecraft:yellow_carpet","minecraft:lime_carpet","minecraft:pink_carpet","minecraft:gray_carpet","minecraft:light_gray_carpet","minecraft:cyan_carpet","minecraft:purple_carpet","minecraft:blue_carpet","minecraft:brown_carpet","minecraft:green_carpet","minecraft:red_carpet","minecraft:black_carpet"],"minecraft:stairs":["minecraft:oak_stairs","minecraft:cobblestone_stairs","minecraft:spruce_stairs","minecraft:sandstone_stairs","minecraft:acacia_stairs","minecraft:jungle_stairs","minecraft:birch_stairs","minecraft:dark_oak_stairs","minecraft:nether_brick_stairs","minecraft:stone_brick_stairs","minecraft:brick_stairs","minecraft:purpur_stairs","minecraft:quartz_stairs","minecraft:red_sandstone_stairs","minecraft:prismarine_brick_stairs","minecraft:prismarine_stairs","minecraft:dark_prismarine_stairs","minecraft:polished_granite_stairs","minecraft:smooth_red_sandstone_stairs","minecraft:mossy_stone_brick_stairs","minecraft:polished_diorite_stairs","minecraft:mossy_cobblestone_stairs","minecraft:end_stone_brick_stairs","minecraft:stone_stairs","minecraft:smooth_sandstone_stairs","minecraft:smooth_quartz_stairs","minecraft:granite_stairs","minecraft:andesite_stairs","minecraft:red_nether_brick_stairs","minecraft:polished_andesite_stairs","minecraft:diorite_stairs"],"minecraft:wooden_doors":["minecraft:oak_door","minecraft:spruce_door","minecraft:birch_door","minecraft:jungle_door","minecraft:acacia_door","minecraft:dark_oak_door"],"minecraft:jungle_logs":["minecraft:jungle_log","minecraft:jungle_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood"],"minecraft:planks":["minecraft:oak_planks","minecraft:spruce_planks","minecraft:birch_planks","minecraft:jungle_planks","minecraft:acacia_planks","minecraft:dark_oak_planks"],"minecraft:wall_corals":["minecraft:tube_coral_wall_fan","minecraft:brain_coral_wall_fan","minecraft:bubble_coral_wall_fan","minecraft:fire_coral_wall_fan","minecraft:horn_coral_wall_fan"],"minecraft:acacia_logs":["minecraft:acacia_log","minecraft:acacia_wood","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood"],"minecraft:wither_immune":["minecraft:barrier","minecraft:bedrock","minecraft:end_portal","minecraft:end_portal_frame","minecraft:end_gateway","minecraft:command_block","minecraft:repeating_command_block","minecraft:chain_command_block","minecraft:structure_block","minecraft:jigsaw","minecraft:moving_piston"],"minecraft:flower_pots":["minecraft:flower_pot","minecraft:potted_poppy","minecraft:potted_blue_orchid","minecraft:potted_allium","minecraft:potted_azure_bluet","minecraft:potted_red_tulip","minecraft:potted_orange_tulip","minecraft:potted_white_tulip","minecraft:potted_pink_tulip","minecraft:potted_oxeye_daisy","minecraft:potted_dandelion","minecraft:potted_oak_sapling","minecraft:potted_spruce_sapling","minecraft:potted_birch_sapling","minecraft:potted_jungle_sapling","minecraft:potted_acacia_sapling","minecraft:potted_dark_oak_sapling","minecraft:potted_red_mushroom","minecraft:potted_brown_mushroom","minecraft:potted_dead_bush","minecraft:potted_fern","minecraft:potted_cactus","minecraft:potted_cornflower","minecraft:potted_lily_of_the_valley","minecraft:potted_wither_rose","minecraft:potted_bamboo"],"minecraft:stone_bricks":["minecraft:stone_bricks","minecraft:mossy_stone_bricks","minecraft:cracked_stone_bricks","minecraft:chiseled_stone_bricks"],"minecraft:enderman_holdable":["minecraft:grass_block","minecraft:dirt","minecraft:coarse_dirt","minecraft:podzol","minecraft:sand","minecraft:red_sand","minecraft:gravel","minecraft:brown_mushroom","minecraft:red_mushroom","minecraft:tnt","minecraft:cactus","minecraft:clay","minecraft:pumpkin","minecraft:carved_pumpkin","minecraft:melon","minecraft:mycelium","minecraft:netherrack","minecraft:dandelion","minecraft:poppy","minecraft:blue_orchid","minecraft:allium","minecraft:azure_bluet","minecraft:red_tulip","minecraft:orange_tulip","minecraft:white_tulip","minecraft:pink_tulip","minecraft:oxeye_daisy","minecraft:cornflower","minecraft:lily_of_the_valley","minecraft:wither_rose"],"minecraft:spruce_logs":["minecraft:spruce_log","minecraft:spruce_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood"],"minecraft:wooden_slabs":["minecraft:oak_slab","minecraft:spruce_slab","minecraft:birch_slab","minecraft:jungle_slab","minecraft:acacia_slab","minecraft:dark_oak_slab"],"minecraft:coral_blocks":["minecraft:tube_coral_block","minecraft:brain_coral_block","minecraft:bubble_coral_block","minecraft:fire_coral_block","minecraft:horn_coral_block"],"minecraft:signs":["minecraft:oak_sign","minecraft:spruce_sign","minecraft:birch_sign","minecraft:acacia_sign","minecraft:jungle_sign","minecraft:dark_oak_sign","minecraft:oak_wall_sign","minecraft:spruce_wall_sign","minecraft:birch_wall_sign","minecraft:acacia_wall_sign","minecraft:jungle_wall_sign","minecraft:dark_oak_wall_sign"],"minecraft:dark_oak_logs":["minecraft:dark_oak_log","minecraft:dark_oak_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood"],"minecraft:sand":["minecraft:sand","minecraft:red_sand"],"minecraft:valid_spawn":["minecraft:grass_block","minecraft:podzol"],"minecraft:underwater_bonemeals":["minecraft:seagrass","minecraft:tube_coral_fan","minecraft:brain_coral_fan","minecraft:bubble_coral_fan","minecraft:fire_coral_fan","minecraft:horn_coral_fan","minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral","minecraft:tube_coral_wall_fan","minecraft:brain_coral_wall_fan","minecraft:bubble_coral_wall_fan","minecraft:fire_coral_wall_fan","minecraft:horn_coral_wall_fan"],"minecraft:oak_logs":["minecraft:oak_log","minecraft:oak_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood"],"minecraft:buttons":["minecraft:stone_button","minecraft:oak_button","minecraft:spruce_button","minecraft:birch_button","minecraft:jungle_button","minecraft:acacia_button","minecraft:dark_oak_button"],"minecraft:wooden_pressure_plates":["minecraft:oak_pressure_plate","minecraft:spruce_pressure_plate","minecraft:birch_pressure_plate","minecraft:jungle_pressure_plate","minecraft:acacia_pressure_plate","minecraft:dark_oak_pressure_plate"],"minecraft:beds":["minecraft:red_bed","minecraft:black_bed","minecraft:blue_bed","minecraft:brown_bed","minecraft:cyan_bed","minecraft:gray_bed","minecraft:green_bed","minecraft:light_blue_bed","minecraft:light_gray_bed","minecraft:lime_bed","minecraft:magenta_bed","minecraft:orange_bed","minecraft:pink_bed","minecraft:purple_bed","minecraft:white_bed","minecraft:yellow_bed"],"minecraft:walls":["minecraft:cobblestone_wall","minecraft:mossy_cobblestone_wall","minecraft:brick_wall","minecraft:prismarine_wall","minecraft:red_sandstone_wall","minecraft:mossy_stone_brick_wall","minecraft:granite_wall","minecraft:stone_brick_wall","minecraft:nether_brick_wall","minecraft:andesite_wall","minecraft:red_nether_brick_wall","minecraft:sandstone_wall","minecraft:end_stone_brick_wall","minecraft:diorite_wall"],"minecraft:rails":["minecraft:rail","minecraft:powered_rail","minecraft:detector_rail","minecraft:activator_rail"],"minecraft:birch_logs":["minecraft:birch_log","minecraft:birch_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood"],"minecraft:wooden_trapdoors":["minecraft:acacia_trapdoor","minecraft:birch_trapdoor","minecraft:dark_oak_trapdoor","minecraft:jungle_trapdoor","minecraft:oak_trapdoor","minecraft:spruce_trapdoor"],"minecraft:wooden_fences":["minecraft:oak_fence","minecraft:acacia_fence","minecraft:dark_oak_fence","minecraft:spruce_fence","minecraft:birch_fence","minecraft:jungle_fence"],"minecraft:saplings":["minecraft:oak_sapling","minecraft:spruce_sapling","minecraft:birch_sapling","minecraft:jungle_sapling","minecraft:acacia_sapling","minecraft:dark_oak_sapling"],"minecraft:small_flowers":["minecraft:dandelion","minecraft:poppy","minecraft:blue_orchid","minecraft:allium","minecraft:azure_bluet","minecraft:red_tulip","minecraft:orange_tulip","minecraft:white_tulip","minecraft:pink_tulip","minecraft:oxeye_daisy","minecraft:cornflower","minecraft:lily_of_the_valley","minecraft:wither_rose"],"minecraft:bamboo_plantable_on":["minecraft:bamboo","minecraft:bamboo_sapling","minecraft:gravel","minecraft:sand","minecraft:red_sand","minecraft:dirt","minecraft:grass_block","minecraft:podzol","minecraft:coarse_dirt","minecraft:mycelium"],"minecraft:ice":["minecraft:ice","minecraft:packed_ice","minecraft:blue_ice","minecraft:frosted_ice"],"minecraft:wooden_stairs":["minecraft:oak_stairs","minecraft:spruce_stairs","minecraft:birch_stairs","minecraft:jungle_stairs","minecraft:acacia_stairs","minecraft:dark_oak_stairs"],"minecraft:anvil":["minecraft:anvil","minecraft:chipped_anvil","minecraft:damaged_anvil"],"minecraft:logs":["minecraft:dark_oak_log","minecraft:dark_oak_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood","minecraft:oak_log","minecraft:oak_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood","minecraft:acacia_log","minecraft:acacia_wood","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood","minecraft:birch_log","minecraft:birch_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood","minecraft:jungle_log","minecraft:jungle_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood","minecraft:spruce_log","minecraft:spruce_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood"],"minecraft:corals":["minecraft:tube_coral_fan","minecraft:brain_coral_fan","minecraft:bubble_coral_fan","minecraft:fire_coral_fan","minecraft:horn_coral_fan","minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral"],"minecraft:wooden_buttons":["minecraft:oak_button","minecraft:spruce_button","minecraft:birch_button","minecraft:jungle_button","minecraft:acacia_button","minecraft:dark_oak_button"],"minecraft:wool":["minecraft:white_wool","minecraft:orange_wool","minecraft:magenta_wool","minecraft:light_blue_wool","minecraft:yellow_wool","minecraft:lime_wool","minecraft:pink_wool","minecraft:gray_wool","minecraft:light_gray_wool","minecraft:cyan_wool","minecraft:purple_wool","minecraft:blue_wool","minecraft:brown_wool","minecraft:green_wool","minecraft:red_wool","minecraft:black_wool"],"minecraft:coral_plants":["minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral"],"minecraft:banners":["minecraft:white_banner","minecraft:orange_banner","minecraft:magenta_banner","minecraft:light_blue_banner","minecraft:yellow_banner","minecraft:lime_banner","minecraft:pink_banner","minecraft:gray_banner","minecraft:light_gray_banner","minecraft:cyan_banner","minecraft:purple_banner","minecraft:blue_banner","minecraft:brown_banner","minecraft:green_banner","minecraft:red_banner","minecraft:black_banner","minecraft:white_wall_banner","minecraft:orange_wall_banner","minecraft:magenta_wall_banner","minecraft:light_blue_wall_banner","minecraft:yellow_wall_banner","minecraft:lime_wall_banner","minecraft:pink_wall_banner","minecraft:gray_wall_banner","minecraft:light_gray_wall_banner","minecraft:cyan_wall_banner","minecraft:purple_wall_banner","minecraft:blue_wall_banner","minecraft:brown_wall_banner","minecraft:green_wall_banner","minecraft:red_wall_banner","minecraft:black_wall_banner"],"minecraft:dragon_immune":["minecraft:barrier","minecraft:bedrock","minecraft:end_portal","minecraft:end_portal_frame","minecraft:end_gateway","minecraft:command_block","minecraft:repeating_command_block","minecraft:chain_command_block","minecraft:structure_block","minecraft:jigsaw","minecraft:moving_piston","minecraft:obsidian","minecraft:end_stone","minecraft:iron_bars"],"minecraft:doors":["minecraft:iron_door","minecraft:oak_door","minecraft:spruce_door","minecraft:birch_door","minecraft:jungle_door","minecraft:acacia_door","minecraft:dark_oak_door"],"minecraft:fences":["minecraft:nether_brick_fence","minecraft:oak_fence","minecraft:acacia_fence","minecraft:dark_oak_fence","minecraft:spruce_fence","minecraft:birch_fence","minecraft:jungle_fence"],"minecraft:wall_signs":["minecraft:oak_wall_sign","minecraft:spruce_wall_sign","minecraft:birch_wall_sign","minecraft:acacia_wall_sign","minecraft:jungle_wall_sign","minecraft:dark_oak_wall_sign"],"minecraft:standing_signs":["minecraft:oak_sign","minecraft:spruce_sign","minecraft:birch_sign","minecraft:acacia_sign","minecraft:jungle_sign","minecraft:dark_oak_sign"],"minecraft:dirt_like":["minecraft:dirt","minecraft:grass_block","minecraft:podzol","minecraft:coarse_dirt","minecraft:mycelium"],"minecraft:impermeable":["minecraft:glass","minecraft:white_stained_glass","minecraft:orange_stained_glass","minecraft:magenta_stained_glass","minecraft:light_blue_stained_glass","minecraft:yellow_stained_glass","minecraft:lime_stained_glass","minecraft:pink_stained_glass","minecraft:gray_stained_glass","minecraft:light_gray_stained_glass","minecraft:cyan_stained_glass","minecraft:purple_stained_glass","minecraft:blue_stained_glass","minecraft:brown_stained_glass","minecraft:green_stained_glass","minecraft:red_stained_glass","minecraft:black_stained_glass"],"minecraft:trapdoors":["minecraft:iron_trapdoor","minecraft:acacia_trapdoor","minecraft:birch_trapdoor","minecraft:dark_oak_trapdoor","minecraft:jungle_trapdoor","minecraft:oak_trapdoor","minecraft:spruce_trapdoor"],"minecraft:leaves":["minecraft:jungle_leaves","minecraft:oak_leaves","minecraft:spruce_leaves","minecraft:dark_oak_leaves","minecraft:acacia_leaves","minecraft:birch_leaves"]},"itemtags":{"minecraft:boats":["minecraft:oak_boat","minecraft:spruce_boat","minecraft:birch_boat","minecraft:jungle_boat","minecraft:acacia_boat","minecraft:dark_oak_boat"],"minecraft:banners":["minecraft:white_banner","minecraft:orange_banner","minecraft:magenta_banner","minecraft:light_blue_banner","minecraft:yellow_banner","minecraft:lime_banner","minecraft:pink_banner","minecraft:gray_banner","minecraft:light_gray_banner","minecraft:cyan_banner","minecraft:purple_banner","minecraft:blue_banner","minecraft:brown_banner","minecraft:green_banner","minecraft:red_banner","minecraft:black_banner"],"minecraft:arrows":["minecraft:arrow","minecraft:tipped_arrow","minecraft:spectral_arrow"],"minecraft:coals":["minecraft:coal","minecraft:charcoal"],"minecraft:music_discs":["minecraft:music_disc_13","minecraft:music_disc_cat","minecraft:music_disc_blocks","minecraft:music_disc_chirp","minecraft:music_disc_far","minecraft:music_disc_mall","minecraft:music_disc_mellohi","minecraft:music_disc_stal","minecraft:music_disc_strad","minecraft:music_disc_ward","minecraft:music_disc_11","minecraft:music_disc_wait"],"minecraft:fishes":["minecraft:cod","minecraft:cooked_cod","minecraft:salmon","minecraft:cooked_salmon","minecraft:pufferfish","minecraft:tropical_fish"]},"entitytags":{"minecraft:raiders":["minecraft:evoker","minecraft:pillager","minecraft:ravager","minecraft:vindicator","minecraft:illusioner","minecraft:witch"],"minecraft:skeletons":["minecraft:skeleton","minecraft:stray","minecraft:wither_skeleton"]}} \ No newline at end of file diff --git a/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1976.json b/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1976.json new file mode 100644 index 000000000..f99217273 --- /dev/null +++ b/worldedit-cli/src/main/resources/com/sk89q/worldedit/cli/data/1976.json @@ -0,0 +1 @@ +{"blocks":{"minecraft:acacia_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_button[face=wall,facing=north,powered=false]"},"minecraft:acacia_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:acacia_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:acacia_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:acacia_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_leaves[distance=7,persistent=false]"},"minecraft:acacia_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:acacia_log[axis=y]"},"minecraft:acacia_planks":{"properties":{},"defaultstate":"minecraft:acacia_planks"},"minecraft:acacia_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_pressure_plate[powered=false]"},"minecraft:acacia_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:acacia_sapling[stage=0]"},"minecraft:acacia_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_sign[rotation=0,waterlogged=false]"},"minecraft:acacia_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_slab[type=bottom,waterlogged=false]"},"minecraft:acacia_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:acacia_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:acacia_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:acacia_wall_sign[facing=north,waterlogged=false]"},"minecraft:acacia_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:acacia_wood[axis=y]"},"minecraft:activator_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:activator_rail[powered=false,shape=north_south]"},"minecraft:air":{"properties":{},"defaultstate":"minecraft:air"},"minecraft:allium":{"properties":{},"defaultstate":"minecraft:allium"},"minecraft:andesite":{"properties":{},"defaultstate":"minecraft:andesite"},"minecraft:andesite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:andesite_slab[type=bottom,waterlogged=false]"},"minecraft:andesite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:andesite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:andesite_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:andesite_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:anvil[facing=north]"},"minecraft:attached_melon_stem":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:attached_melon_stem[facing=north]"},"minecraft:attached_pumpkin_stem":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:attached_pumpkin_stem[facing=north]"},"minecraft:azure_bluet":{"properties":{},"defaultstate":"minecraft:azure_bluet"},"minecraft:bamboo":{"properties":{"age":{"values":["0","1"],"type":"int"},"leaves":{"values":["none","small","large"],"type":"enum"},"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:bamboo[age=0,leaves=none,stage=0]"},"minecraft:bamboo_sapling":{"properties":{},"defaultstate":"minecraft:bamboo_sapling"},"minecraft:barrel":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"open":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:barrel[facing=north,open=false]"},"minecraft:barrier":{"properties":{},"defaultstate":"minecraft:barrier"},"minecraft:beacon":{"properties":{},"defaultstate":"minecraft:beacon"},"minecraft:bedrock":{"properties":{},"defaultstate":"minecraft:bedrock"},"minecraft:beetroots":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:beetroots[age=0]"},"minecraft:bell":{"properties":{"attachment":{"values":["floor","ceiling","single_wall","double_wall"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:bell[attachment=floor,facing=north]"},"minecraft:birch_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_button[face=wall,facing=north,powered=false]"},"minecraft:birch_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:birch_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:birch_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:birch_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_leaves[distance=7,persistent=false]"},"minecraft:birch_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:birch_log[axis=y]"},"minecraft:birch_planks":{"properties":{},"defaultstate":"minecraft:birch_planks"},"minecraft:birch_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_pressure_plate[powered=false]"},"minecraft:birch_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:birch_sapling[stage=0]"},"minecraft:birch_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_sign[rotation=0,waterlogged=false]"},"minecraft:birch_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_slab[type=bottom,waterlogged=false]"},"minecraft:birch_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:birch_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:birch_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:birch_wall_sign[facing=north,waterlogged=false]"},"minecraft:birch_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:birch_wood[axis=y]"},"minecraft:black_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:black_banner[rotation=0]"},"minecraft:black_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:black_bed[facing=north,occupied=false,part=foot]"},"minecraft:black_carpet":{"properties":{},"defaultstate":"minecraft:black_carpet"},"minecraft:black_concrete":{"properties":{},"defaultstate":"minecraft:black_concrete"},"minecraft:black_concrete_powder":{"properties":{},"defaultstate":"minecraft:black_concrete_powder"},"minecraft:black_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:black_glazed_terracotta[facing=north]"},"minecraft:black_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:black_shulker_box[facing=up]"},"minecraft:black_stained_glass":{"properties":{},"defaultstate":"minecraft:black_stained_glass"},"minecraft:black_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:black_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:black_terracotta":{"properties":{},"defaultstate":"minecraft:black_terracotta"},"minecraft:black_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:black_wall_banner[facing=north]"},"minecraft:black_wool":{"properties":{},"defaultstate":"minecraft:black_wool"},"minecraft:blast_furnace":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:blast_furnace[facing=north,lit=false]"},"minecraft:blue_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:blue_banner[rotation=0]"},"minecraft:blue_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:blue_bed[facing=north,occupied=false,part=foot]"},"minecraft:blue_carpet":{"properties":{},"defaultstate":"minecraft:blue_carpet"},"minecraft:blue_concrete":{"properties":{},"defaultstate":"minecraft:blue_concrete"},"minecraft:blue_concrete_powder":{"properties":{},"defaultstate":"minecraft:blue_concrete_powder"},"minecraft:blue_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:blue_glazed_terracotta[facing=north]"},"minecraft:blue_ice":{"properties":{},"defaultstate":"minecraft:blue_ice"},"minecraft:blue_orchid":{"properties":{},"defaultstate":"minecraft:blue_orchid"},"minecraft:blue_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:blue_shulker_box[facing=up]"},"minecraft:blue_stained_glass":{"properties":{},"defaultstate":"minecraft:blue_stained_glass"},"minecraft:blue_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:blue_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:blue_terracotta":{"properties":{},"defaultstate":"minecraft:blue_terracotta"},"minecraft:blue_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:blue_wall_banner[facing=north]"},"minecraft:blue_wool":{"properties":{},"defaultstate":"minecraft:blue_wool"},"minecraft:bone_block":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:bone_block[axis=y]"},"minecraft:bookshelf":{"properties":{},"defaultstate":"minecraft:bookshelf"},"minecraft:brain_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral[waterlogged=true]"},"minecraft:brain_coral_block":{"properties":{},"defaultstate":"minecraft:brain_coral_block"},"minecraft:brain_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral_fan[waterlogged=true]"},"minecraft:brain_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brain_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:brewing_stand":{"properties":{"has_bottle_0":{"values":["true","false"],"type":"bool"},"has_bottle_1":{"values":["true","false"],"type":"bool"},"has_bottle_2":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brewing_stand[has_bottle_0=false,has_bottle_1=false,has_bottle_2=false]"},"minecraft:brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_slab[type=bottom,waterlogged=false]"},"minecraft:brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:bricks":{"properties":{},"defaultstate":"minecraft:bricks"},"minecraft:brown_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:brown_banner[rotation=0]"},"minecraft:brown_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:brown_bed[facing=north,occupied=false,part=foot]"},"minecraft:brown_carpet":{"properties":{},"defaultstate":"minecraft:brown_carpet"},"minecraft:brown_concrete":{"properties":{},"defaultstate":"minecraft:brown_concrete"},"minecraft:brown_concrete_powder":{"properties":{},"defaultstate":"minecraft:brown_concrete_powder"},"minecraft:brown_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:brown_glazed_terracotta[facing=north]"},"minecraft:brown_mushroom":{"properties":{},"defaultstate":"minecraft:brown_mushroom"},"minecraft:brown_mushroom_block":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:brown_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:brown_shulker_box[facing=up]"},"minecraft:brown_stained_glass":{"properties":{},"defaultstate":"minecraft:brown_stained_glass"},"minecraft:brown_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:brown_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:brown_terracotta":{"properties":{},"defaultstate":"minecraft:brown_terracotta"},"minecraft:brown_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:brown_wall_banner[facing=north]"},"minecraft:brown_wool":{"properties":{},"defaultstate":"minecraft:brown_wool"},"minecraft:bubble_column":{"properties":{"drag":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_column[drag=true]"},"minecraft:bubble_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral[waterlogged=true]"},"minecraft:bubble_coral_block":{"properties":{},"defaultstate":"minecraft:bubble_coral_block"},"minecraft:bubble_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral_fan[waterlogged=true]"},"minecraft:bubble_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:bubble_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:cactus":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:cactus[age=0]"},"minecraft:cake":{"properties":{"bites":{"values":["0","1","2","3","4","5","6"],"type":"int"}},"defaultstate":"minecraft:cake[bites=0]"},"minecraft:campfire":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"},"signal_fire":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:campfire[facing=north,lit=true,signal_fire=false,waterlogged=false]"},"minecraft:carrots":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:carrots[age=0]"},"minecraft:cartography_table":{"properties":{},"defaultstate":"minecraft:cartography_table"},"minecraft:carved_pumpkin":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:carved_pumpkin[facing=north]"},"minecraft:cauldron":{"properties":{"level":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:cauldron[level=0]"},"minecraft:cave_air":{"properties":{},"defaultstate":"minecraft:cave_air"},"minecraft:chain_command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:chain_command_block[conditional=false,facing=north]"},"minecraft:chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"type":{"values":["single","left","right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:chest[facing=north,type=single,waterlogged=false]"},"minecraft:chipped_anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:chipped_anvil[facing=north]"},"minecraft:chiseled_quartz_block":{"properties":{},"defaultstate":"minecraft:chiseled_quartz_block"},"minecraft:chiseled_red_sandstone":{"properties":{},"defaultstate":"minecraft:chiseled_red_sandstone"},"minecraft:chiseled_sandstone":{"properties":{},"defaultstate":"minecraft:chiseled_sandstone"},"minecraft:chiseled_stone_bricks":{"properties":{},"defaultstate":"minecraft:chiseled_stone_bricks"},"minecraft:chorus_flower":{"properties":{"age":{"values":["0","1","2","3","4","5"],"type":"int"}},"defaultstate":"minecraft:chorus_flower[age=0]"},"minecraft:chorus_plant":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]"},"minecraft:clay":{"properties":{},"defaultstate":"minecraft:clay"},"minecraft:coal_block":{"properties":{},"defaultstate":"minecraft:coal_block"},"minecraft:coal_ore":{"properties":{},"defaultstate":"minecraft:coal_ore"},"minecraft:coarse_dirt":{"properties":{},"defaultstate":"minecraft:coarse_dirt"},"minecraft:cobblestone":{"properties":{},"defaultstate":"minecraft:cobblestone"},"minecraft:cobblestone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_slab[type=bottom,waterlogged=false]"},"minecraft:cobblestone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:cobblestone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cobblestone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:cobweb":{"properties":{},"defaultstate":"minecraft:cobweb"},"minecraft:cocoa":{"properties":{"age":{"values":["0","1","2"],"type":"int"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cocoa[age=0,facing=north]"},"minecraft:command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:command_block[conditional=false,facing=north]"},"minecraft:comparator":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"mode":{"values":["compare","subtract"],"type":"enum"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:comparator[facing=north,mode=compare,powered=false]"},"minecraft:composter":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8"],"type":"int"}},"defaultstate":"minecraft:composter[level=0]"},"minecraft:conduit":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:conduit[waterlogged=true]"},"minecraft:cornflower":{"properties":{},"defaultstate":"minecraft:cornflower"},"minecraft:cracked_stone_bricks":{"properties":{},"defaultstate":"minecraft:cracked_stone_bricks"},"minecraft:crafting_table":{"properties":{},"defaultstate":"minecraft:crafting_table"},"minecraft:creeper_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:creeper_head[rotation=0]"},"minecraft:creeper_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:creeper_wall_head[facing=north]"},"minecraft:cut_red_sandstone":{"properties":{},"defaultstate":"minecraft:cut_red_sandstone"},"minecraft:cut_red_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cut_red_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:cut_sandstone":{"properties":{},"defaultstate":"minecraft:cut_sandstone"},"minecraft:cut_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cut_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:cyan_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:cyan_banner[rotation=0]"},"minecraft:cyan_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:cyan_bed[facing=north,occupied=false,part=foot]"},"minecraft:cyan_carpet":{"properties":{},"defaultstate":"minecraft:cyan_carpet"},"minecraft:cyan_concrete":{"properties":{},"defaultstate":"minecraft:cyan_concrete"},"minecraft:cyan_concrete_powder":{"properties":{},"defaultstate":"minecraft:cyan_concrete_powder"},"minecraft:cyan_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cyan_glazed_terracotta[facing=north]"},"minecraft:cyan_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:cyan_shulker_box[facing=up]"},"minecraft:cyan_stained_glass":{"properties":{},"defaultstate":"minecraft:cyan_stained_glass"},"minecraft:cyan_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:cyan_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:cyan_terracotta":{"properties":{},"defaultstate":"minecraft:cyan_terracotta"},"minecraft:cyan_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:cyan_wall_banner[facing=north]"},"minecraft:cyan_wool":{"properties":{},"defaultstate":"minecraft:cyan_wool"},"minecraft:damaged_anvil":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:damaged_anvil[facing=north]"},"minecraft:dandelion":{"properties":{},"defaultstate":"minecraft:dandelion"},"minecraft:dark_oak_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_button[face=wall,facing=north,powered=false]"},"minecraft:dark_oak_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:dark_oak_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:dark_oak_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:dark_oak_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_leaves[distance=7,persistent=false]"},"minecraft:dark_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:dark_oak_log[axis=y]"},"minecraft:dark_oak_planks":{"properties":{},"defaultstate":"minecraft:dark_oak_planks"},"minecraft:dark_oak_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_pressure_plate[powered=false]"},"minecraft:dark_oak_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:dark_oak_sapling[stage=0]"},"minecraft:dark_oak_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_sign[rotation=0,waterlogged=false]"},"minecraft:dark_oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_slab[type=bottom,waterlogged=false]"},"minecraft:dark_oak_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:dark_oak_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:dark_oak_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_oak_wall_sign[facing=north,waterlogged=false]"},"minecraft:dark_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:dark_oak_wood[axis=y]"},"minecraft:dark_prismarine":{"properties":{},"defaultstate":"minecraft:dark_prismarine"},"minecraft:dark_prismarine_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_prismarine_slab[type=bottom,waterlogged=false]"},"minecraft:dark_prismarine_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dark_prismarine_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:daylight_detector":{"properties":{"inverted":{"values":["true","false"],"type":"bool"},"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:daylight_detector[inverted=false,power=0]"},"minecraft:dead_brain_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral[waterlogged=true]"},"minecraft:dead_brain_coral_block":{"properties":{},"defaultstate":"minecraft:dead_brain_coral_block"},"minecraft:dead_brain_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral_fan[waterlogged=true]"},"minecraft:dead_brain_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_brain_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_bubble_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral[waterlogged=true]"},"minecraft:dead_bubble_coral_block":{"properties":{},"defaultstate":"minecraft:dead_bubble_coral_block"},"minecraft:dead_bubble_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral_fan[waterlogged=true]"},"minecraft:dead_bubble_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_bubble_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_bush":{"properties":{},"defaultstate":"minecraft:dead_bush"},"minecraft:dead_fire_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral[waterlogged=true]"},"minecraft:dead_fire_coral_block":{"properties":{},"defaultstate":"minecraft:dead_fire_coral_block"},"minecraft:dead_fire_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral_fan[waterlogged=true]"},"minecraft:dead_fire_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_fire_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_horn_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral[waterlogged=true]"},"minecraft:dead_horn_coral_block":{"properties":{},"defaultstate":"minecraft:dead_horn_coral_block"},"minecraft:dead_horn_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral_fan[waterlogged=true]"},"minecraft:dead_horn_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_horn_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:dead_tube_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral[waterlogged=true]"},"minecraft:dead_tube_coral_block":{"properties":{},"defaultstate":"minecraft:dead_tube_coral_block"},"minecraft:dead_tube_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral_fan[waterlogged=true]"},"minecraft:dead_tube_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dead_tube_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:detector_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:detector_rail[powered=false,shape=north_south]"},"minecraft:diamond_block":{"properties":{},"defaultstate":"minecraft:diamond_block"},"minecraft:diamond_ore":{"properties":{},"defaultstate":"minecraft:diamond_ore"},"minecraft:diorite":{"properties":{},"defaultstate":"minecraft:diorite"},"minecraft:diorite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:diorite_slab[type=bottom,waterlogged=false]"},"minecraft:diorite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:diorite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:diorite_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:diorite_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:dirt":{"properties":{},"defaultstate":"minecraft:dirt"},"minecraft:dispenser":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"triggered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dispenser[facing=north,triggered=false]"},"minecraft:dragon_egg":{"properties":{},"defaultstate":"minecraft:dragon_egg"},"minecraft:dragon_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:dragon_head[rotation=0]"},"minecraft:dragon_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:dragon_wall_head[facing=north]"},"minecraft:dried_kelp_block":{"properties":{},"defaultstate":"minecraft:dried_kelp_block"},"minecraft:dropper":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"triggered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:dropper[facing=north,triggered=false]"},"minecraft:emerald_block":{"properties":{},"defaultstate":"minecraft:emerald_block"},"minecraft:emerald_ore":{"properties":{},"defaultstate":"minecraft:emerald_ore"},"minecraft:enchanting_table":{"properties":{},"defaultstate":"minecraft:enchanting_table"},"minecraft:end_gateway":{"properties":{},"defaultstate":"minecraft:end_gateway"},"minecraft:end_portal":{"properties":{},"defaultstate":"minecraft:end_portal"},"minecraft:end_portal_frame":{"properties":{"eye":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:end_portal_frame[eye=false,facing=north]"},"minecraft:end_rod":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:end_rod[facing=up]"},"minecraft:end_stone":{"properties":{},"defaultstate":"minecraft:end_stone"},"minecraft:end_stone_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:end_stone_brick_slab[type=bottom,waterlogged=false]"},"minecraft:end_stone_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:end_stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:end_stone_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:end_stone_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:end_stone_bricks":{"properties":{},"defaultstate":"minecraft:end_stone_bricks"},"minecraft:ender_chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:ender_chest[facing=north,waterlogged=false]"},"minecraft:farmland":{"properties":{"moisture":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:farmland[moisture=0]"},"minecraft:fern":{"properties":{},"defaultstate":"minecraft:fern"},"minecraft:fire":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire[age=0,east=false,north=false,south=false,up=false,west=false]"},"minecraft:fire_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral[waterlogged=true]"},"minecraft:fire_coral_block":{"properties":{},"defaultstate":"minecraft:fire_coral_block"},"minecraft:fire_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral_fan[waterlogged=true]"},"minecraft:fire_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:fire_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:fletching_table":{"properties":{},"defaultstate":"minecraft:fletching_table"},"minecraft:flower_pot":{"properties":{},"defaultstate":"minecraft:flower_pot"},"minecraft:frosted_ice":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:frosted_ice[age=0]"},"minecraft:furnace":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:furnace[facing=north,lit=false]"},"minecraft:glass":{"properties":{},"defaultstate":"minecraft:glass"},"minecraft:glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:glowstone":{"properties":{},"defaultstate":"minecraft:glowstone"},"minecraft:gold_block":{"properties":{},"defaultstate":"minecraft:gold_block"},"minecraft:gold_ore":{"properties":{},"defaultstate":"minecraft:gold_ore"},"minecraft:granite":{"properties":{},"defaultstate":"minecraft:granite"},"minecraft:granite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:granite_slab[type=bottom,waterlogged=false]"},"minecraft:granite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:granite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:granite_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:granite_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:grass":{"properties":{},"defaultstate":"minecraft:grass"},"minecraft:grass_block":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:grass_block[snowy=false]"},"minecraft:grass_path":{"properties":{},"defaultstate":"minecraft:grass_path"},"minecraft:gravel":{"properties":{},"defaultstate":"minecraft:gravel"},"minecraft:gray_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:gray_banner[rotation=0]"},"minecraft:gray_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:gray_bed[facing=north,occupied=false,part=foot]"},"minecraft:gray_carpet":{"properties":{},"defaultstate":"minecraft:gray_carpet"},"minecraft:gray_concrete":{"properties":{},"defaultstate":"minecraft:gray_concrete"},"minecraft:gray_concrete_powder":{"properties":{},"defaultstate":"minecraft:gray_concrete_powder"},"minecraft:gray_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:gray_glazed_terracotta[facing=north]"},"minecraft:gray_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:gray_shulker_box[facing=up]"},"minecraft:gray_stained_glass":{"properties":{},"defaultstate":"minecraft:gray_stained_glass"},"minecraft:gray_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:gray_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:gray_terracotta":{"properties":{},"defaultstate":"minecraft:gray_terracotta"},"minecraft:gray_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:gray_wall_banner[facing=north]"},"minecraft:gray_wool":{"properties":{},"defaultstate":"minecraft:gray_wool"},"minecraft:green_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:green_banner[rotation=0]"},"minecraft:green_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:green_bed[facing=north,occupied=false,part=foot]"},"minecraft:green_carpet":{"properties":{},"defaultstate":"minecraft:green_carpet"},"minecraft:green_concrete":{"properties":{},"defaultstate":"minecraft:green_concrete"},"minecraft:green_concrete_powder":{"properties":{},"defaultstate":"minecraft:green_concrete_powder"},"minecraft:green_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:green_glazed_terracotta[facing=north]"},"minecraft:green_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:green_shulker_box[facing=up]"},"minecraft:green_stained_glass":{"properties":{},"defaultstate":"minecraft:green_stained_glass"},"minecraft:green_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:green_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:green_terracotta":{"properties":{},"defaultstate":"minecraft:green_terracotta"},"minecraft:green_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:green_wall_banner[facing=north]"},"minecraft:green_wool":{"properties":{},"defaultstate":"minecraft:green_wool"},"minecraft:grindstone":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:grindstone[face=wall,facing=north]"},"minecraft:hay_block":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:hay_block[axis=y]"},"minecraft:heavy_weighted_pressure_plate":{"properties":{"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:heavy_weighted_pressure_plate[power=0]"},"minecraft:hopper":{"properties":{"enabled":{"values":["true","false"],"type":"bool"},"facing":{"values":["down","north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:hopper[enabled=true,facing=down]"},"minecraft:horn_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral[waterlogged=true]"},"minecraft:horn_coral_block":{"properties":{},"defaultstate":"minecraft:horn_coral_block"},"minecraft:horn_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral_fan[waterlogged=true]"},"minecraft:horn_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:horn_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:ice":{"properties":{},"defaultstate":"minecraft:ice"},"minecraft:infested_chiseled_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_chiseled_stone_bricks"},"minecraft:infested_cobblestone":{"properties":{},"defaultstate":"minecraft:infested_cobblestone"},"minecraft:infested_cracked_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_cracked_stone_bricks"},"minecraft:infested_mossy_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_mossy_stone_bricks"},"minecraft:infested_stone":{"properties":{},"defaultstate":"minecraft:infested_stone"},"minecraft:infested_stone_bricks":{"properties":{},"defaultstate":"minecraft:infested_stone_bricks"},"minecraft:iron_bars":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_bars[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:iron_block":{"properties":{},"defaultstate":"minecraft:iron_block"},"minecraft:iron_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:iron_ore":{"properties":{},"defaultstate":"minecraft:iron_ore"},"minecraft:iron_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:jack_o_lantern":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:jack_o_lantern[facing=north]"},"minecraft:jigsaw":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:jigsaw[facing=up]"},"minecraft:jukebox":{"properties":{"has_record":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jukebox[has_record=false]"},"minecraft:jungle_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_button[face=wall,facing=north,powered=false]"},"minecraft:jungle_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:jungle_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:jungle_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:jungle_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_leaves[distance=7,persistent=false]"},"minecraft:jungle_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:jungle_log[axis=y]"},"minecraft:jungle_planks":{"properties":{},"defaultstate":"minecraft:jungle_planks"},"minecraft:jungle_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_pressure_plate[powered=false]"},"minecraft:jungle_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:jungle_sapling[stage=0]"},"minecraft:jungle_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_sign[rotation=0,waterlogged=false]"},"minecraft:jungle_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_slab[type=bottom,waterlogged=false]"},"minecraft:jungle_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:jungle_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:jungle_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:jungle_wall_sign[facing=north,waterlogged=false]"},"minecraft:jungle_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:jungle_wood[axis=y]"},"minecraft:kelp":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25"],"type":"int"}},"defaultstate":"minecraft:kelp[age=0]"},"minecraft:kelp_plant":{"properties":{},"defaultstate":"minecraft:kelp_plant"},"minecraft:ladder":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:ladder[facing=north,waterlogged=false]"},"minecraft:lantern":{"properties":{"hanging":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lantern[hanging=false]"},"minecraft:lapis_block":{"properties":{},"defaultstate":"minecraft:lapis_block"},"minecraft:lapis_ore":{"properties":{},"defaultstate":"minecraft:lapis_ore"},"minecraft:large_fern":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:large_fern[half=lower]"},"minecraft:lava":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:lava[level=0]"},"minecraft:lectern":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"has_book":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lectern[facing=north,has_book=false,powered=false]"},"minecraft:lever":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lever[face=wall,facing=north,powered=false]"},"minecraft:light_blue_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_blue_banner[rotation=0]"},"minecraft:light_blue_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:light_blue_bed[facing=north,occupied=false,part=foot]"},"minecraft:light_blue_carpet":{"properties":{},"defaultstate":"minecraft:light_blue_carpet"},"minecraft:light_blue_concrete":{"properties":{},"defaultstate":"minecraft:light_blue_concrete"},"minecraft:light_blue_concrete_powder":{"properties":{},"defaultstate":"minecraft:light_blue_concrete_powder"},"minecraft:light_blue_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_blue_glazed_terracotta[facing=north]"},"minecraft:light_blue_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:light_blue_shulker_box[facing=up]"},"minecraft:light_blue_stained_glass":{"properties":{},"defaultstate":"minecraft:light_blue_stained_glass"},"minecraft:light_blue_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:light_blue_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:light_blue_terracotta":{"properties":{},"defaultstate":"minecraft:light_blue_terracotta"},"minecraft:light_blue_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_blue_wall_banner[facing=north]"},"minecraft:light_blue_wool":{"properties":{},"defaultstate":"minecraft:light_blue_wool"},"minecraft:light_gray_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_gray_banner[rotation=0]"},"minecraft:light_gray_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:light_gray_bed[facing=north,occupied=false,part=foot]"},"minecraft:light_gray_carpet":{"properties":{},"defaultstate":"minecraft:light_gray_carpet"},"minecraft:light_gray_concrete":{"properties":{},"defaultstate":"minecraft:light_gray_concrete"},"minecraft:light_gray_concrete_powder":{"properties":{},"defaultstate":"minecraft:light_gray_concrete_powder"},"minecraft:light_gray_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_gray_glazed_terracotta[facing=north]"},"minecraft:light_gray_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:light_gray_shulker_box[facing=up]"},"minecraft:light_gray_stained_glass":{"properties":{},"defaultstate":"minecraft:light_gray_stained_glass"},"minecraft:light_gray_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:light_gray_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:light_gray_terracotta":{"properties":{},"defaultstate":"minecraft:light_gray_terracotta"},"minecraft:light_gray_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:light_gray_wall_banner[facing=north]"},"minecraft:light_gray_wool":{"properties":{},"defaultstate":"minecraft:light_gray_wool"},"minecraft:light_weighted_pressure_plate":{"properties":{"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:light_weighted_pressure_plate[power=0]"},"minecraft:lilac":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:lilac[half=lower]"},"minecraft:lily_of_the_valley":{"properties":{},"defaultstate":"minecraft:lily_of_the_valley"},"minecraft:lily_pad":{"properties":{},"defaultstate":"minecraft:lily_pad"},"minecraft:lime_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:lime_banner[rotation=0]"},"minecraft:lime_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:lime_bed[facing=north,occupied=false,part=foot]"},"minecraft:lime_carpet":{"properties":{},"defaultstate":"minecraft:lime_carpet"},"minecraft:lime_concrete":{"properties":{},"defaultstate":"minecraft:lime_concrete"},"minecraft:lime_concrete_powder":{"properties":{},"defaultstate":"minecraft:lime_concrete_powder"},"minecraft:lime_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:lime_glazed_terracotta[facing=north]"},"minecraft:lime_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:lime_shulker_box[facing=up]"},"minecraft:lime_stained_glass":{"properties":{},"defaultstate":"minecraft:lime_stained_glass"},"minecraft:lime_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:lime_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:lime_terracotta":{"properties":{},"defaultstate":"minecraft:lime_terracotta"},"minecraft:lime_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:lime_wall_banner[facing=north]"},"minecraft:lime_wool":{"properties":{},"defaultstate":"minecraft:lime_wool"},"minecraft:loom":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:loom[facing=north]"},"minecraft:magenta_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:magenta_banner[rotation=0]"},"minecraft:magenta_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:magenta_bed[facing=north,occupied=false,part=foot]"},"minecraft:magenta_carpet":{"properties":{},"defaultstate":"minecraft:magenta_carpet"},"minecraft:magenta_concrete":{"properties":{},"defaultstate":"minecraft:magenta_concrete"},"minecraft:magenta_concrete_powder":{"properties":{},"defaultstate":"minecraft:magenta_concrete_powder"},"minecraft:magenta_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:magenta_glazed_terracotta[facing=north]"},"minecraft:magenta_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:magenta_shulker_box[facing=up]"},"minecraft:magenta_stained_glass":{"properties":{},"defaultstate":"minecraft:magenta_stained_glass"},"minecraft:magenta_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:magenta_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:magenta_terracotta":{"properties":{},"defaultstate":"minecraft:magenta_terracotta"},"minecraft:magenta_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:magenta_wall_banner[facing=north]"},"minecraft:magenta_wool":{"properties":{},"defaultstate":"minecraft:magenta_wool"},"minecraft:magma_block":{"properties":{},"defaultstate":"minecraft:magma_block"},"minecraft:melon":{"properties":{},"defaultstate":"minecraft:melon"},"minecraft:melon_stem":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:melon_stem[age=0]"},"minecraft:mossy_cobblestone":{"properties":{},"defaultstate":"minecraft:mossy_cobblestone"},"minecraft:mossy_cobblestone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_cobblestone_slab[type=bottom,waterlogged=false]"},"minecraft:mossy_cobblestone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_cobblestone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:mossy_cobblestone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_cobblestone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:mossy_stone_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_stone_brick_slab[type=bottom,waterlogged=false]"},"minecraft:mossy_stone_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:mossy_stone_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mossy_stone_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:mossy_stone_bricks":{"properties":{},"defaultstate":"minecraft:mossy_stone_bricks"},"minecraft:moving_piston":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"type":{"values":["normal","sticky"],"type":"enum"}},"defaultstate":"minecraft:moving_piston[facing=north,type=normal]"},"minecraft:mushroom_stem":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:mycelium":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:mycelium[snowy=false]"},"minecraft:nether_brick_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:nether_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_slab[type=bottom,waterlogged=false]"},"minecraft:nether_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:nether_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:nether_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:nether_bricks":{"properties":{},"defaultstate":"minecraft:nether_bricks"},"minecraft:nether_portal":{"properties":{"axis":{"values":["x","z"],"type":"enum"}},"defaultstate":"minecraft:nether_portal[axis=x]"},"minecraft:nether_quartz_ore":{"properties":{},"defaultstate":"minecraft:nether_quartz_ore"},"minecraft:nether_wart":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:nether_wart[age=0]"},"minecraft:nether_wart_block":{"properties":{},"defaultstate":"minecraft:nether_wart_block"},"minecraft:netherrack":{"properties":{},"defaultstate":"minecraft:netherrack"},"minecraft:note_block":{"properties":{"instrument":{"values":["harp","basedrum","snare","hat","bass","flute","bell","guitar","chime","xylophone","iron_xylophone","cow_bell","didgeridoo","bit","banjo","pling"],"type":"enum"},"note":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24"],"type":"int"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:note_block[instrument=harp,note=0,powered=false]"},"minecraft:oak_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_button[face=wall,facing=north,powered=false]"},"minecraft:oak_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:oak_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:oak_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:oak_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_leaves[distance=7,persistent=false]"},"minecraft:oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:oak_log[axis=y]"},"minecraft:oak_planks":{"properties":{},"defaultstate":"minecraft:oak_planks"},"minecraft:oak_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_pressure_plate[powered=false]"},"minecraft:oak_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:oak_sapling[stage=0]"},"minecraft:oak_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_sign[rotation=0,waterlogged=false]"},"minecraft:oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_slab[type=bottom,waterlogged=false]"},"minecraft:oak_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:oak_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:oak_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:oak_wall_sign[facing=north,waterlogged=false]"},"minecraft:oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:oak_wood[axis=y]"},"minecraft:observer":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:observer[facing=south,powered=false]"},"minecraft:obsidian":{"properties":{},"defaultstate":"minecraft:obsidian"},"minecraft:orange_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:orange_banner[rotation=0]"},"minecraft:orange_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:orange_bed[facing=north,occupied=false,part=foot]"},"minecraft:orange_carpet":{"properties":{},"defaultstate":"minecraft:orange_carpet"},"minecraft:orange_concrete":{"properties":{},"defaultstate":"minecraft:orange_concrete"},"minecraft:orange_concrete_powder":{"properties":{},"defaultstate":"minecraft:orange_concrete_powder"},"minecraft:orange_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:orange_glazed_terracotta[facing=north]"},"minecraft:orange_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:orange_shulker_box[facing=up]"},"minecraft:orange_stained_glass":{"properties":{},"defaultstate":"minecraft:orange_stained_glass"},"minecraft:orange_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:orange_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:orange_terracotta":{"properties":{},"defaultstate":"minecraft:orange_terracotta"},"minecraft:orange_tulip":{"properties":{},"defaultstate":"minecraft:orange_tulip"},"minecraft:orange_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:orange_wall_banner[facing=north]"},"minecraft:orange_wool":{"properties":{},"defaultstate":"minecraft:orange_wool"},"minecraft:oxeye_daisy":{"properties":{},"defaultstate":"minecraft:oxeye_daisy"},"minecraft:packed_ice":{"properties":{},"defaultstate":"minecraft:packed_ice"},"minecraft:peony":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:peony[half=lower]"},"minecraft:petrified_oak_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:petrified_oak_slab[type=bottom,waterlogged=false]"},"minecraft:pink_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:pink_banner[rotation=0]"},"minecraft:pink_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:pink_bed[facing=north,occupied=false,part=foot]"},"minecraft:pink_carpet":{"properties":{},"defaultstate":"minecraft:pink_carpet"},"minecraft:pink_concrete":{"properties":{},"defaultstate":"minecraft:pink_concrete"},"minecraft:pink_concrete_powder":{"properties":{},"defaultstate":"minecraft:pink_concrete_powder"},"minecraft:pink_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:pink_glazed_terracotta[facing=north]"},"minecraft:pink_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:pink_shulker_box[facing=up]"},"minecraft:pink_stained_glass":{"properties":{},"defaultstate":"minecraft:pink_stained_glass"},"minecraft:pink_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:pink_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:pink_terracotta":{"properties":{},"defaultstate":"minecraft:pink_terracotta"},"minecraft:pink_tulip":{"properties":{},"defaultstate":"minecraft:pink_tulip"},"minecraft:pink_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:pink_wall_banner[facing=north]"},"minecraft:pink_wool":{"properties":{},"defaultstate":"minecraft:pink_wool"},"minecraft:piston":{"properties":{"extended":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:piston[extended=false,facing=north]"},"minecraft:piston_head":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"},"short":{"values":["true","false"],"type":"bool"},"type":{"values":["normal","sticky"],"type":"enum"}},"defaultstate":"minecraft:piston_head[facing=north,short=false,type=normal]"},"minecraft:player_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:player_head[rotation=0]"},"minecraft:player_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:player_wall_head[facing=north]"},"minecraft:podzol":{"properties":{"snowy":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:podzol[snowy=false]"},"minecraft:polished_andesite":{"properties":{},"defaultstate":"minecraft:polished_andesite"},"minecraft:polished_andesite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_andesite_slab[type=bottom,waterlogged=false]"},"minecraft:polished_andesite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_andesite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:polished_diorite":{"properties":{},"defaultstate":"minecraft:polished_diorite"},"minecraft:polished_diorite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_diorite_slab[type=bottom,waterlogged=false]"},"minecraft:polished_diorite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_diorite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:polished_granite":{"properties":{},"defaultstate":"minecraft:polished_granite"},"minecraft:polished_granite_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_granite_slab[type=bottom,waterlogged=false]"},"minecraft:polished_granite_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:polished_granite_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:poppy":{"properties":{},"defaultstate":"minecraft:poppy"},"minecraft:potatoes":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:potatoes[age=0]"},"minecraft:potted_acacia_sapling":{"properties":{},"defaultstate":"minecraft:potted_acacia_sapling"},"minecraft:potted_allium":{"properties":{},"defaultstate":"minecraft:potted_allium"},"minecraft:potted_azure_bluet":{"properties":{},"defaultstate":"minecraft:potted_azure_bluet"},"minecraft:potted_bamboo":{"properties":{},"defaultstate":"minecraft:potted_bamboo"},"minecraft:potted_birch_sapling":{"properties":{},"defaultstate":"minecraft:potted_birch_sapling"},"minecraft:potted_blue_orchid":{"properties":{},"defaultstate":"minecraft:potted_blue_orchid"},"minecraft:potted_brown_mushroom":{"properties":{},"defaultstate":"minecraft:potted_brown_mushroom"},"minecraft:potted_cactus":{"properties":{},"defaultstate":"minecraft:potted_cactus"},"minecraft:potted_cornflower":{"properties":{},"defaultstate":"minecraft:potted_cornflower"},"minecraft:potted_dandelion":{"properties":{},"defaultstate":"minecraft:potted_dandelion"},"minecraft:potted_dark_oak_sapling":{"properties":{},"defaultstate":"minecraft:potted_dark_oak_sapling"},"minecraft:potted_dead_bush":{"properties":{},"defaultstate":"minecraft:potted_dead_bush"},"minecraft:potted_fern":{"properties":{},"defaultstate":"minecraft:potted_fern"},"minecraft:potted_jungle_sapling":{"properties":{},"defaultstate":"minecraft:potted_jungle_sapling"},"minecraft:potted_lily_of_the_valley":{"properties":{},"defaultstate":"minecraft:potted_lily_of_the_valley"},"minecraft:potted_oak_sapling":{"properties":{},"defaultstate":"minecraft:potted_oak_sapling"},"minecraft:potted_orange_tulip":{"properties":{},"defaultstate":"minecraft:potted_orange_tulip"},"minecraft:potted_oxeye_daisy":{"properties":{},"defaultstate":"minecraft:potted_oxeye_daisy"},"minecraft:potted_pink_tulip":{"properties":{},"defaultstate":"minecraft:potted_pink_tulip"},"minecraft:potted_poppy":{"properties":{},"defaultstate":"minecraft:potted_poppy"},"minecraft:potted_red_mushroom":{"properties":{},"defaultstate":"minecraft:potted_red_mushroom"},"minecraft:potted_red_tulip":{"properties":{},"defaultstate":"minecraft:potted_red_tulip"},"minecraft:potted_spruce_sapling":{"properties":{},"defaultstate":"minecraft:potted_spruce_sapling"},"minecraft:potted_white_tulip":{"properties":{},"defaultstate":"minecraft:potted_white_tulip"},"minecraft:potted_wither_rose":{"properties":{},"defaultstate":"minecraft:potted_wither_rose"},"minecraft:powered_rail":{"properties":{"powered":{"values":["true","false"],"type":"bool"},"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south"],"type":"enum"}},"defaultstate":"minecraft:powered_rail[powered=false,shape=north_south]"},"minecraft:prismarine":{"properties":{},"defaultstate":"minecraft:prismarine"},"minecraft:prismarine_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_brick_slab[type=bottom,waterlogged=false]"},"minecraft:prismarine_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:prismarine_bricks":{"properties":{},"defaultstate":"minecraft:prismarine_bricks"},"minecraft:prismarine_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_slab[type=bottom,waterlogged=false]"},"minecraft:prismarine_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:prismarine_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:prismarine_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:pumpkin":{"properties":{},"defaultstate":"minecraft:pumpkin"},"minecraft:pumpkin_stem":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:pumpkin_stem[age=0]"},"minecraft:purple_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:purple_banner[rotation=0]"},"minecraft:purple_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:purple_bed[facing=north,occupied=false,part=foot]"},"minecraft:purple_carpet":{"properties":{},"defaultstate":"minecraft:purple_carpet"},"minecraft:purple_concrete":{"properties":{},"defaultstate":"minecraft:purple_concrete"},"minecraft:purple_concrete_powder":{"properties":{},"defaultstate":"minecraft:purple_concrete_powder"},"minecraft:purple_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:purple_glazed_terracotta[facing=north]"},"minecraft:purple_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:purple_shulker_box[facing=up]"},"minecraft:purple_stained_glass":{"properties":{},"defaultstate":"minecraft:purple_stained_glass"},"minecraft:purple_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purple_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:purple_terracotta":{"properties":{},"defaultstate":"minecraft:purple_terracotta"},"minecraft:purple_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:purple_wall_banner[facing=north]"},"minecraft:purple_wool":{"properties":{},"defaultstate":"minecraft:purple_wool"},"minecraft:purpur_block":{"properties":{},"defaultstate":"minecraft:purpur_block"},"minecraft:purpur_pillar":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:purpur_pillar[axis=y]"},"minecraft:purpur_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purpur_slab[type=bottom,waterlogged=false]"},"minecraft:purpur_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:purpur_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:quartz_block":{"properties":{},"defaultstate":"minecraft:quartz_block"},"minecraft:quartz_pillar":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:quartz_pillar[axis=y]"},"minecraft:quartz_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:quartz_slab[type=bottom,waterlogged=false]"},"minecraft:quartz_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:quartz_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:rail":{"properties":{"shape":{"values":["north_south","east_west","ascending_east","ascending_west","ascending_north","ascending_south","south_east","south_west","north_west","north_east"],"type":"enum"}},"defaultstate":"minecraft:rail[shape=north_south]"},"minecraft:red_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:red_banner[rotation=0]"},"minecraft:red_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:red_bed[facing=north,occupied=false,part=foot]"},"minecraft:red_carpet":{"properties":{},"defaultstate":"minecraft:red_carpet"},"minecraft:red_concrete":{"properties":{},"defaultstate":"minecraft:red_concrete"},"minecraft:red_concrete_powder":{"properties":{},"defaultstate":"minecraft:red_concrete_powder"},"minecraft:red_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:red_glazed_terracotta[facing=north]"},"minecraft:red_mushroom":{"properties":{},"defaultstate":"minecraft:red_mushroom"},"minecraft:red_mushroom_block":{"properties":{"down":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true]"},"minecraft:red_nether_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_nether_brick_slab[type=bottom,waterlogged=false]"},"minecraft:red_nether_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_nether_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:red_nether_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_nether_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:red_nether_bricks":{"properties":{},"defaultstate":"minecraft:red_nether_bricks"},"minecraft:red_sand":{"properties":{},"defaultstate":"minecraft:red_sand"},"minecraft:red_sandstone":{"properties":{},"defaultstate":"minecraft:red_sandstone"},"minecraft:red_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:red_sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:red_sandstone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_sandstone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:red_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:red_shulker_box[facing=up]"},"minecraft:red_stained_glass":{"properties":{},"defaultstate":"minecraft:red_stained_glass"},"minecraft:red_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:red_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:red_terracotta":{"properties":{},"defaultstate":"minecraft:red_terracotta"},"minecraft:red_tulip":{"properties":{},"defaultstate":"minecraft:red_tulip"},"minecraft:red_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:red_wall_banner[facing=north]"},"minecraft:red_wool":{"properties":{},"defaultstate":"minecraft:red_wool"},"minecraft:redstone_block":{"properties":{},"defaultstate":"minecraft:redstone_block"},"minecraft:redstone_lamp":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_lamp[lit=false]"},"minecraft:redstone_ore":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_ore[lit=false]"},"minecraft:redstone_torch":{"properties":{"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_torch[lit=true]"},"minecraft:redstone_wall_torch":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:redstone_wall_torch[facing=north,lit=true]"},"minecraft:redstone_wire":{"properties":{"east":{"values":["up","side","none"],"type":"enum"},"north":{"values":["up","side","none"],"type":"enum"},"power":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"south":{"values":["up","side","none"],"type":"enum"},"west":{"values":["up","side","none"],"type":"enum"}},"defaultstate":"minecraft:redstone_wire[east=none,north=none,power=0,south=none,west=none]"},"minecraft:repeater":{"properties":{"delay":{"values":["1","2","3","4"],"type":"int"},"facing":{"values":["north","south","west","east"],"type":"direction"},"locked":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:repeater[delay=1,facing=north,locked=false,powered=false]"},"minecraft:repeating_command_block":{"properties":{"conditional":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:repeating_command_block[conditional=false,facing=north]"},"minecraft:rose_bush":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:rose_bush[half=lower]"},"minecraft:sand":{"properties":{},"defaultstate":"minecraft:sand"},"minecraft:sandstone":{"properties":{},"defaultstate":"minecraft:sandstone"},"minecraft:sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:sandstone_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sandstone_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:scaffolding":{"properties":{"bottom":{"values":["true","false"],"type":"bool"},"distance":{"values":["0","1","2","3","4","5","6","7"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:scaffolding[bottom=false,distance=7,waterlogged=false]"},"minecraft:sea_lantern":{"properties":{},"defaultstate":"minecraft:sea_lantern"},"minecraft:sea_pickle":{"properties":{"pickles":{"values":["1","2","3","4"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:sea_pickle[pickles=1,waterlogged=true]"},"minecraft:seagrass":{"properties":{},"defaultstate":"minecraft:seagrass"},"minecraft:shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:shulker_box[facing=up]"},"minecraft:skeleton_skull":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:skeleton_skull[rotation=0]"},"minecraft:skeleton_wall_skull":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:skeleton_wall_skull[facing=north]"},"minecraft:slime_block":{"properties":{},"defaultstate":"minecraft:slime_block"},"minecraft:smithing_table":{"properties":{},"defaultstate":"minecraft:smithing_table"},"minecraft:smoker":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"lit":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smoker[facing=north,lit=false]"},"minecraft:smooth_quartz":{"properties":{},"defaultstate":"minecraft:smooth_quartz"},"minecraft:smooth_quartz_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_quartz_slab[type=bottom,waterlogged=false]"},"minecraft:smooth_quartz_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_quartz_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:smooth_red_sandstone":{"properties":{},"defaultstate":"minecraft:smooth_red_sandstone"},"minecraft:smooth_red_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_red_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:smooth_red_sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_red_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:smooth_sandstone":{"properties":{},"defaultstate":"minecraft:smooth_sandstone"},"minecraft:smooth_sandstone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_sandstone_slab[type=bottom,waterlogged=false]"},"minecraft:smooth_sandstone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_sandstone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:smooth_stone":{"properties":{},"defaultstate":"minecraft:smooth_stone"},"minecraft:smooth_stone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:smooth_stone_slab[type=bottom,waterlogged=false]"},"minecraft:snow":{"properties":{"layers":{"values":["1","2","3","4","5","6","7","8"],"type":"int"}},"defaultstate":"minecraft:snow[layers=1]"},"minecraft:snow_block":{"properties":{},"defaultstate":"minecraft:snow_block"},"minecraft:soul_sand":{"properties":{},"defaultstate":"minecraft:soul_sand"},"minecraft:spawner":{"properties":{},"defaultstate":"minecraft:spawner"},"minecraft:sponge":{"properties":{},"defaultstate":"minecraft:sponge"},"minecraft:spruce_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_button[face=wall,facing=north,powered=false]"},"minecraft:spruce_door":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["upper","lower"],"type":"enum"},"hinge":{"values":["left","right"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_door[facing=north,half=lower,hinge=left,open=false,powered=false]"},"minecraft:spruce_fence":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_fence[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:spruce_fence_gate":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"in_wall":{"values":["true","false"],"type":"bool"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_fence_gate[facing=north,in_wall=false,open=false,powered=false]"},"minecraft:spruce_leaves":{"properties":{"distance":{"values":["1","2","3","4","5","6","7"],"type":"int"},"persistent":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_leaves[distance=7,persistent=false]"},"minecraft:spruce_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:spruce_log[axis=y]"},"minecraft:spruce_planks":{"properties":{},"defaultstate":"minecraft:spruce_planks"},"minecraft:spruce_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_pressure_plate[powered=false]"},"minecraft:spruce_sapling":{"properties":{"stage":{"values":["0","1"],"type":"int"}},"defaultstate":"minecraft:spruce_sapling[stage=0]"},"minecraft:spruce_sign":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_sign[rotation=0,waterlogged=false]"},"minecraft:spruce_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_slab[type=bottom,waterlogged=false]"},"minecraft:spruce_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:spruce_trapdoor":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"open":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false]"},"minecraft:spruce_wall_sign":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:spruce_wall_sign[facing=north,waterlogged=false]"},"minecraft:spruce_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:spruce_wood[axis=y]"},"minecraft:sticky_piston":{"properties":{"extended":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:sticky_piston[extended=false,facing=north]"},"minecraft:stone":{"properties":{},"defaultstate":"minecraft:stone"},"minecraft:stone_brick_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_slab[type=bottom,waterlogged=false]"},"minecraft:stone_brick_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:stone_brick_wall":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_brick_wall[east=false,north=false,south=false,up=true,waterlogged=false,west=false]"},"minecraft:stone_bricks":{"properties":{},"defaultstate":"minecraft:stone_bricks"},"minecraft:stone_button":{"properties":{"face":{"values":["floor","wall","ceiling"],"type":"enum"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_button[face=wall,facing=north,powered=false]"},"minecraft:stone_pressure_plate":{"properties":{"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_pressure_plate[powered=false]"},"minecraft:stone_slab":{"properties":{"type":{"values":["top","bottom","double"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_slab[type=bottom,waterlogged=false]"},"minecraft:stone_stairs":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"half":{"values":["top","bottom"],"type":"enum"},"shape":{"values":["straight","inner_left","inner_right","outer_left","outer_right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:stone_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]"},"minecraft:stonecutter":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:stonecutter[facing=north]"},"minecraft:stripped_acacia_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_acacia_log[axis=y]"},"minecraft:stripped_acacia_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_acacia_wood[axis=y]"},"minecraft:stripped_birch_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_birch_log[axis=y]"},"minecraft:stripped_birch_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_birch_wood[axis=y]"},"minecraft:stripped_dark_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_dark_oak_log[axis=y]"},"minecraft:stripped_dark_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_dark_oak_wood[axis=y]"},"minecraft:stripped_jungle_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_jungle_log[axis=y]"},"minecraft:stripped_jungle_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_jungle_wood[axis=y]"},"minecraft:stripped_oak_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_oak_log[axis=y]"},"minecraft:stripped_oak_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_oak_wood[axis=y]"},"minecraft:stripped_spruce_log":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_spruce_log[axis=y]"},"minecraft:stripped_spruce_wood":{"properties":{"axis":{"values":["x","y","z"],"type":"enum"}},"defaultstate":"minecraft:stripped_spruce_wood[axis=y]"},"minecraft:structure_block":{"properties":{"mode":{"values":["save","load","corner","data"],"type":"enum"}},"defaultstate":"minecraft:structure_block[mode=save]"},"minecraft:structure_void":{"properties":{},"defaultstate":"minecraft:structure_void"},"minecraft:sugar_cane":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:sugar_cane[age=0]"},"minecraft:sunflower":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:sunflower[half=lower]"},"minecraft:sweet_berry_bush":{"properties":{"age":{"values":["0","1","2","3"],"type":"int"}},"defaultstate":"minecraft:sweet_berry_bush[age=0]"},"minecraft:tall_grass":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:tall_grass[half=lower]"},"minecraft:tall_seagrass":{"properties":{"half":{"values":["upper","lower"],"type":"enum"}},"defaultstate":"minecraft:tall_seagrass[half=lower]"},"minecraft:terracotta":{"properties":{},"defaultstate":"minecraft:terracotta"},"minecraft:tnt":{"properties":{"unstable":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tnt[unstable=false]"},"minecraft:torch":{"properties":{},"defaultstate":"minecraft:torch"},"minecraft:trapped_chest":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"type":{"values":["single","left","right"],"type":"enum"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:trapped_chest[facing=north,type=single,waterlogged=false]"},"minecraft:tripwire":{"properties":{"attached":{"values":["true","false"],"type":"bool"},"disarmed":{"values":["true","false"],"type":"bool"},"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"powered":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,powered=false,south=false,west=false]"},"minecraft:tripwire_hook":{"properties":{"attached":{"values":["true","false"],"type":"bool"},"facing":{"values":["north","south","west","east"],"type":"direction"},"powered":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tripwire_hook[attached=false,facing=north,powered=false]"},"minecraft:tube_coral":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral[waterlogged=true]"},"minecraft:tube_coral_block":{"properties":{},"defaultstate":"minecraft:tube_coral_block"},"minecraft:tube_coral_fan":{"properties":{"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral_fan[waterlogged=true]"},"minecraft:tube_coral_wall_fan":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"waterlogged":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:tube_coral_wall_fan[facing=north,waterlogged=true]"},"minecraft:turtle_egg":{"properties":{"eggs":{"values":["1","2","3","4"],"type":"int"},"hatch":{"values":["0","1","2"],"type":"int"}},"defaultstate":"minecraft:turtle_egg[eggs=1,hatch=0]"},"minecraft:vine":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"up":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:vine[east=false,north=false,south=false,up=false,west=false]"},"minecraft:void_air":{"properties":{},"defaultstate":"minecraft:void_air"},"minecraft:wall_torch":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:wall_torch[facing=north]"},"minecraft:water":{"properties":{"level":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:water[level=0]"},"minecraft:wet_sponge":{"properties":{},"defaultstate":"minecraft:wet_sponge"},"minecraft:wheat":{"properties":{"age":{"values":["0","1","2","3","4","5","6","7"],"type":"int"}},"defaultstate":"minecraft:wheat[age=0]"},"minecraft:white_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:white_banner[rotation=0]"},"minecraft:white_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:white_bed[facing=north,occupied=false,part=foot]"},"minecraft:white_carpet":{"properties":{},"defaultstate":"minecraft:white_carpet"},"minecraft:white_concrete":{"properties":{},"defaultstate":"minecraft:white_concrete"},"minecraft:white_concrete_powder":{"properties":{},"defaultstate":"minecraft:white_concrete_powder"},"minecraft:white_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:white_glazed_terracotta[facing=north]"},"minecraft:white_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:white_shulker_box[facing=up]"},"minecraft:white_stained_glass":{"properties":{},"defaultstate":"minecraft:white_stained_glass"},"minecraft:white_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:white_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:white_terracotta":{"properties":{},"defaultstate":"minecraft:white_terracotta"},"minecraft:white_tulip":{"properties":{},"defaultstate":"minecraft:white_tulip"},"minecraft:white_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:white_wall_banner[facing=north]"},"minecraft:white_wool":{"properties":{},"defaultstate":"minecraft:white_wool"},"minecraft:wither_rose":{"properties":{},"defaultstate":"minecraft:wither_rose"},"minecraft:wither_skeleton_skull":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:wither_skeleton_skull[rotation=0]"},"minecraft:wither_skeleton_wall_skull":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:wither_skeleton_wall_skull[facing=north]"},"minecraft:yellow_banner":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:yellow_banner[rotation=0]"},"minecraft:yellow_bed":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"},"occupied":{"values":["true","false"],"type":"bool"},"part":{"values":["head","foot"],"type":"enum"}},"defaultstate":"minecraft:yellow_bed[facing=north,occupied=false,part=foot]"},"minecraft:yellow_carpet":{"properties":{},"defaultstate":"minecraft:yellow_carpet"},"minecraft:yellow_concrete":{"properties":{},"defaultstate":"minecraft:yellow_concrete"},"minecraft:yellow_concrete_powder":{"properties":{},"defaultstate":"minecraft:yellow_concrete_powder"},"minecraft:yellow_glazed_terracotta":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:yellow_glazed_terracotta[facing=north]"},"minecraft:yellow_shulker_box":{"properties":{"facing":{"values":["north","east","south","west","up","down"],"type":"direction"}},"defaultstate":"minecraft:yellow_shulker_box[facing=up]"},"minecraft:yellow_stained_glass":{"properties":{},"defaultstate":"minecraft:yellow_stained_glass"},"minecraft:yellow_stained_glass_pane":{"properties":{"east":{"values":["true","false"],"type":"bool"},"north":{"values":["true","false"],"type":"bool"},"south":{"values":["true","false"],"type":"bool"},"waterlogged":{"values":["true","false"],"type":"bool"},"west":{"values":["true","false"],"type":"bool"}},"defaultstate":"minecraft:yellow_stained_glass_pane[east=false,north=false,south=false,waterlogged=false,west=false]"},"minecraft:yellow_terracotta":{"properties":{},"defaultstate":"minecraft:yellow_terracotta"},"minecraft:yellow_wall_banner":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:yellow_wall_banner[facing=north]"},"minecraft:yellow_wool":{"properties":{},"defaultstate":"minecraft:yellow_wool"},"minecraft:zombie_head":{"properties":{"rotation":{"values":["0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"],"type":"int"}},"defaultstate":"minecraft:zombie_head[rotation=0]"},"minecraft:zombie_wall_head":{"properties":{"facing":{"values":["north","south","west","east"],"type":"direction"}},"defaultstate":"minecraft:zombie_wall_head[facing=north]"}},"items":["minecraft:acacia_boat","minecraft:acacia_button","minecraft:acacia_door","minecraft:acacia_fence","minecraft:acacia_fence_gate","minecraft:acacia_leaves","minecraft:acacia_log","minecraft:acacia_planks","minecraft:acacia_pressure_plate","minecraft:acacia_sapling","minecraft:acacia_sign","minecraft:acacia_slab","minecraft:acacia_stairs","minecraft:acacia_trapdoor","minecraft:acacia_wood","minecraft:activator_rail","minecraft:air","minecraft:allium","minecraft:andesite","minecraft:andesite_slab","minecraft:andesite_stairs","minecraft:andesite_wall","minecraft:anvil","minecraft:apple","minecraft:armor_stand","minecraft:arrow","minecraft:azure_bluet","minecraft:baked_potato","minecraft:bamboo","minecraft:barrel","minecraft:barrier","minecraft:bat_spawn_egg","minecraft:beacon","minecraft:bedrock","minecraft:beef","minecraft:beetroot","minecraft:beetroot_seeds","minecraft:beetroot_soup","minecraft:bell","minecraft:birch_boat","minecraft:birch_button","minecraft:birch_door","minecraft:birch_fence","minecraft:birch_fence_gate","minecraft:birch_leaves","minecraft:birch_log","minecraft:birch_planks","minecraft:birch_pressure_plate","minecraft:birch_sapling","minecraft:birch_sign","minecraft:birch_slab","minecraft:birch_stairs","minecraft:birch_trapdoor","minecraft:birch_wood","minecraft:black_banner","minecraft:black_bed","minecraft:black_carpet","minecraft:black_concrete","minecraft:black_concrete_powder","minecraft:black_dye","minecraft:black_glazed_terracotta","minecraft:black_shulker_box","minecraft:black_stained_glass","minecraft:black_stained_glass_pane","minecraft:black_terracotta","minecraft:black_wool","minecraft:blast_furnace","minecraft:blaze_powder","minecraft:blaze_rod","minecraft:blaze_spawn_egg","minecraft:blue_banner","minecraft:blue_bed","minecraft:blue_carpet","minecraft:blue_concrete","minecraft:blue_concrete_powder","minecraft:blue_dye","minecraft:blue_glazed_terracotta","minecraft:blue_ice","minecraft:blue_orchid","minecraft:blue_shulker_box","minecraft:blue_stained_glass","minecraft:blue_stained_glass_pane","minecraft:blue_terracotta","minecraft:blue_wool","minecraft:bone","minecraft:bone_block","minecraft:bone_meal","minecraft:book","minecraft:bookshelf","minecraft:bow","minecraft:bowl","minecraft:brain_coral","minecraft:brain_coral_block","minecraft:brain_coral_fan","minecraft:bread","minecraft:brewing_stand","minecraft:brick","minecraft:brick_slab","minecraft:brick_stairs","minecraft:brick_wall","minecraft:bricks","minecraft:brown_banner","minecraft:brown_bed","minecraft:brown_carpet","minecraft:brown_concrete","minecraft:brown_concrete_powder","minecraft:brown_dye","minecraft:brown_glazed_terracotta","minecraft:brown_mushroom","minecraft:brown_mushroom_block","minecraft:brown_shulker_box","minecraft:brown_stained_glass","minecraft:brown_stained_glass_pane","minecraft:brown_terracotta","minecraft:brown_wool","minecraft:bubble_coral","minecraft:bubble_coral_block","minecraft:bubble_coral_fan","minecraft:bucket","minecraft:cactus","minecraft:cake","minecraft:campfire","minecraft:carrot","minecraft:carrot_on_a_stick","minecraft:cartography_table","minecraft:carved_pumpkin","minecraft:cat_spawn_egg","minecraft:cauldron","minecraft:cave_spider_spawn_egg","minecraft:chain_command_block","minecraft:chainmail_boots","minecraft:chainmail_chestplate","minecraft:chainmail_helmet","minecraft:chainmail_leggings","minecraft:charcoal","minecraft:chest","minecraft:chest_minecart","minecraft:chicken","minecraft:chicken_spawn_egg","minecraft:chipped_anvil","minecraft:chiseled_quartz_block","minecraft:chiseled_red_sandstone","minecraft:chiseled_sandstone","minecraft:chiseled_stone_bricks","minecraft:chorus_flower","minecraft:chorus_fruit","minecraft:chorus_plant","minecraft:clay","minecraft:clay_ball","minecraft:clock","minecraft:coal","minecraft:coal_block","minecraft:coal_ore","minecraft:coarse_dirt","minecraft:cobblestone","minecraft:cobblestone_slab","minecraft:cobblestone_stairs","minecraft:cobblestone_wall","minecraft:cobweb","minecraft:cocoa_beans","minecraft:cod","minecraft:cod_bucket","minecraft:cod_spawn_egg","minecraft:command_block","minecraft:command_block_minecart","minecraft:comparator","minecraft:compass","minecraft:composter","minecraft:conduit","minecraft:cooked_beef","minecraft:cooked_chicken","minecraft:cooked_cod","minecraft:cooked_mutton","minecraft:cooked_porkchop","minecraft:cooked_rabbit","minecraft:cooked_salmon","minecraft:cookie","minecraft:cornflower","minecraft:cow_spawn_egg","minecraft:cracked_stone_bricks","minecraft:crafting_table","minecraft:creeper_banner_pattern","minecraft:creeper_head","minecraft:creeper_spawn_egg","minecraft:crossbow","minecraft:cut_red_sandstone","minecraft:cut_red_sandstone_slab","minecraft:cut_sandstone","minecraft:cut_sandstone_slab","minecraft:cyan_banner","minecraft:cyan_bed","minecraft:cyan_carpet","minecraft:cyan_concrete","minecraft:cyan_concrete_powder","minecraft:cyan_dye","minecraft:cyan_glazed_terracotta","minecraft:cyan_shulker_box","minecraft:cyan_stained_glass","minecraft:cyan_stained_glass_pane","minecraft:cyan_terracotta","minecraft:cyan_wool","minecraft:damaged_anvil","minecraft:dandelion","minecraft:dark_oak_boat","minecraft:dark_oak_button","minecraft:dark_oak_door","minecraft:dark_oak_fence","minecraft:dark_oak_fence_gate","minecraft:dark_oak_leaves","minecraft:dark_oak_log","minecraft:dark_oak_planks","minecraft:dark_oak_pressure_plate","minecraft:dark_oak_sapling","minecraft:dark_oak_sign","minecraft:dark_oak_slab","minecraft:dark_oak_stairs","minecraft:dark_oak_trapdoor","minecraft:dark_oak_wood","minecraft:dark_prismarine","minecraft:dark_prismarine_slab","minecraft:dark_prismarine_stairs","minecraft:daylight_detector","minecraft:dead_brain_coral","minecraft:dead_brain_coral_block","minecraft:dead_brain_coral_fan","minecraft:dead_bubble_coral","minecraft:dead_bubble_coral_block","minecraft:dead_bubble_coral_fan","minecraft:dead_bush","minecraft:dead_fire_coral","minecraft:dead_fire_coral_block","minecraft:dead_fire_coral_fan","minecraft:dead_horn_coral","minecraft:dead_horn_coral_block","minecraft:dead_horn_coral_fan","minecraft:dead_tube_coral","minecraft:dead_tube_coral_block","minecraft:dead_tube_coral_fan","minecraft:debug_stick","minecraft:detector_rail","minecraft:diamond","minecraft:diamond_axe","minecraft:diamond_block","minecraft:diamond_boots","minecraft:diamond_chestplate","minecraft:diamond_helmet","minecraft:diamond_hoe","minecraft:diamond_horse_armor","minecraft:diamond_leggings","minecraft:diamond_ore","minecraft:diamond_pickaxe","minecraft:diamond_shovel","minecraft:diamond_sword","minecraft:diorite","minecraft:diorite_slab","minecraft:diorite_stairs","minecraft:diorite_wall","minecraft:dirt","minecraft:dispenser","minecraft:dolphin_spawn_egg","minecraft:donkey_spawn_egg","minecraft:dragon_breath","minecraft:dragon_egg","minecraft:dragon_head","minecraft:dried_kelp","minecraft:dried_kelp_block","minecraft:dropper","minecraft:drowned_spawn_egg","minecraft:egg","minecraft:elder_guardian_spawn_egg","minecraft:elytra","minecraft:emerald","minecraft:emerald_block","minecraft:emerald_ore","minecraft:enchanted_book","minecraft:enchanted_golden_apple","minecraft:enchanting_table","minecraft:end_crystal","minecraft:end_portal_frame","minecraft:end_rod","minecraft:end_stone","minecraft:end_stone_brick_slab","minecraft:end_stone_brick_stairs","minecraft:end_stone_brick_wall","minecraft:end_stone_bricks","minecraft:ender_chest","minecraft:ender_eye","minecraft:ender_pearl","minecraft:enderman_spawn_egg","minecraft:endermite_spawn_egg","minecraft:evoker_spawn_egg","minecraft:experience_bottle","minecraft:farmland","minecraft:feather","minecraft:fermented_spider_eye","minecraft:fern","minecraft:filled_map","minecraft:fire_charge","minecraft:fire_coral","minecraft:fire_coral_block","minecraft:fire_coral_fan","minecraft:firework_rocket","minecraft:firework_star","minecraft:fishing_rod","minecraft:fletching_table","minecraft:flint","minecraft:flint_and_steel","minecraft:flower_banner_pattern","minecraft:flower_pot","minecraft:fox_spawn_egg","minecraft:furnace","minecraft:furnace_minecart","minecraft:ghast_spawn_egg","minecraft:ghast_tear","minecraft:glass","minecraft:glass_bottle","minecraft:glass_pane","minecraft:glistering_melon_slice","minecraft:globe_banner_pattern","minecraft:glowstone","minecraft:glowstone_dust","minecraft:gold_block","minecraft:gold_ingot","minecraft:gold_nugget","minecraft:gold_ore","minecraft:golden_apple","minecraft:golden_axe","minecraft:golden_boots","minecraft:golden_carrot","minecraft:golden_chestplate","minecraft:golden_helmet","minecraft:golden_hoe","minecraft:golden_horse_armor","minecraft:golden_leggings","minecraft:golden_pickaxe","minecraft:golden_shovel","minecraft:golden_sword","minecraft:granite","minecraft:granite_slab","minecraft:granite_stairs","minecraft:granite_wall","minecraft:grass","minecraft:grass_block","minecraft:grass_path","minecraft:gravel","minecraft:gray_banner","minecraft:gray_bed","minecraft:gray_carpet","minecraft:gray_concrete","minecraft:gray_concrete_powder","minecraft:gray_dye","minecraft:gray_glazed_terracotta","minecraft:gray_shulker_box","minecraft:gray_stained_glass","minecraft:gray_stained_glass_pane","minecraft:gray_terracotta","minecraft:gray_wool","minecraft:green_banner","minecraft:green_bed","minecraft:green_carpet","minecraft:green_concrete","minecraft:green_concrete_powder","minecraft:green_dye","minecraft:green_glazed_terracotta","minecraft:green_shulker_box","minecraft:green_stained_glass","minecraft:green_stained_glass_pane","minecraft:green_terracotta","minecraft:green_wool","minecraft:grindstone","minecraft:guardian_spawn_egg","minecraft:gunpowder","minecraft:hay_block","minecraft:heart_of_the_sea","minecraft:heavy_weighted_pressure_plate","minecraft:hopper","minecraft:hopper_minecart","minecraft:horn_coral","minecraft:horn_coral_block","minecraft:horn_coral_fan","minecraft:horse_spawn_egg","minecraft:husk_spawn_egg","minecraft:ice","minecraft:infested_chiseled_stone_bricks","minecraft:infested_cobblestone","minecraft:infested_cracked_stone_bricks","minecraft:infested_mossy_stone_bricks","minecraft:infested_stone","minecraft:infested_stone_bricks","minecraft:ink_sac","minecraft:iron_axe","minecraft:iron_bars","minecraft:iron_block","minecraft:iron_boots","minecraft:iron_chestplate","minecraft:iron_door","minecraft:iron_helmet","minecraft:iron_hoe","minecraft:iron_horse_armor","minecraft:iron_ingot","minecraft:iron_leggings","minecraft:iron_nugget","minecraft:iron_ore","minecraft:iron_pickaxe","minecraft:iron_shovel","minecraft:iron_sword","minecraft:iron_trapdoor","minecraft:item_frame","minecraft:jack_o_lantern","minecraft:jigsaw","minecraft:jukebox","minecraft:jungle_boat","minecraft:jungle_button","minecraft:jungle_door","minecraft:jungle_fence","minecraft:jungle_fence_gate","minecraft:jungle_leaves","minecraft:jungle_log","minecraft:jungle_planks","minecraft:jungle_pressure_plate","minecraft:jungle_sapling","minecraft:jungle_sign","minecraft:jungle_slab","minecraft:jungle_stairs","minecraft:jungle_trapdoor","minecraft:jungle_wood","minecraft:kelp","minecraft:knowledge_book","minecraft:ladder","minecraft:lantern","minecraft:lapis_block","minecraft:lapis_lazuli","minecraft:lapis_ore","minecraft:large_fern","minecraft:lava_bucket","minecraft:lead","minecraft:leather","minecraft:leather_boots","minecraft:leather_chestplate","minecraft:leather_helmet","minecraft:leather_horse_armor","minecraft:leather_leggings","minecraft:lectern","minecraft:lever","minecraft:light_blue_banner","minecraft:light_blue_bed","minecraft:light_blue_carpet","minecraft:light_blue_concrete","minecraft:light_blue_concrete_powder","minecraft:light_blue_dye","minecraft:light_blue_glazed_terracotta","minecraft:light_blue_shulker_box","minecraft:light_blue_stained_glass","minecraft:light_blue_stained_glass_pane","minecraft:light_blue_terracotta","minecraft:light_blue_wool","minecraft:light_gray_banner","minecraft:light_gray_bed","minecraft:light_gray_carpet","minecraft:light_gray_concrete","minecraft:light_gray_concrete_powder","minecraft:light_gray_dye","minecraft:light_gray_glazed_terracotta","minecraft:light_gray_shulker_box","minecraft:light_gray_stained_glass","minecraft:light_gray_stained_glass_pane","minecraft:light_gray_terracotta","minecraft:light_gray_wool","minecraft:light_weighted_pressure_plate","minecraft:lilac","minecraft:lily_of_the_valley","minecraft:lily_pad","minecraft:lime_banner","minecraft:lime_bed","minecraft:lime_carpet","minecraft:lime_concrete","minecraft:lime_concrete_powder","minecraft:lime_dye","minecraft:lime_glazed_terracotta","minecraft:lime_shulker_box","minecraft:lime_stained_glass","minecraft:lime_stained_glass_pane","minecraft:lime_terracotta","minecraft:lime_wool","minecraft:lingering_potion","minecraft:llama_spawn_egg","minecraft:loom","minecraft:magenta_banner","minecraft:magenta_bed","minecraft:magenta_carpet","minecraft:magenta_concrete","minecraft:magenta_concrete_powder","minecraft:magenta_dye","minecraft:magenta_glazed_terracotta","minecraft:magenta_shulker_box","minecraft:magenta_stained_glass","minecraft:magenta_stained_glass_pane","minecraft:magenta_terracotta","minecraft:magenta_wool","minecraft:magma_block","minecraft:magma_cream","minecraft:magma_cube_spawn_egg","minecraft:map","minecraft:melon","minecraft:melon_seeds","minecraft:melon_slice","minecraft:milk_bucket","minecraft:minecart","minecraft:mojang_banner_pattern","minecraft:mooshroom_spawn_egg","minecraft:mossy_cobblestone","minecraft:mossy_cobblestone_slab","minecraft:mossy_cobblestone_stairs","minecraft:mossy_cobblestone_wall","minecraft:mossy_stone_brick_slab","minecraft:mossy_stone_brick_stairs","minecraft:mossy_stone_brick_wall","minecraft:mossy_stone_bricks","minecraft:mule_spawn_egg","minecraft:mushroom_stem","minecraft:mushroom_stew","minecraft:music_disc_11","minecraft:music_disc_13","minecraft:music_disc_blocks","minecraft:music_disc_cat","minecraft:music_disc_chirp","minecraft:music_disc_far","minecraft:music_disc_mall","minecraft:music_disc_mellohi","minecraft:music_disc_stal","minecraft:music_disc_strad","minecraft:music_disc_wait","minecraft:music_disc_ward","minecraft:mutton","minecraft:mycelium","minecraft:name_tag","minecraft:nautilus_shell","minecraft:nether_brick","minecraft:nether_brick_fence","minecraft:nether_brick_slab","minecraft:nether_brick_stairs","minecraft:nether_brick_wall","minecraft:nether_bricks","minecraft:nether_quartz_ore","minecraft:nether_star","minecraft:nether_wart","minecraft:nether_wart_block","minecraft:netherrack","minecraft:note_block","minecraft:oak_boat","minecraft:oak_button","minecraft:oak_door","minecraft:oak_fence","minecraft:oak_fence_gate","minecraft:oak_leaves","minecraft:oak_log","minecraft:oak_planks","minecraft:oak_pressure_plate","minecraft:oak_sapling","minecraft:oak_sign","minecraft:oak_slab","minecraft:oak_stairs","minecraft:oak_trapdoor","minecraft:oak_wood","minecraft:observer","minecraft:obsidian","minecraft:ocelot_spawn_egg","minecraft:orange_banner","minecraft:orange_bed","minecraft:orange_carpet","minecraft:orange_concrete","minecraft:orange_concrete_powder","minecraft:orange_dye","minecraft:orange_glazed_terracotta","minecraft:orange_shulker_box","minecraft:orange_stained_glass","minecraft:orange_stained_glass_pane","minecraft:orange_terracotta","minecraft:orange_tulip","minecraft:orange_wool","minecraft:oxeye_daisy","minecraft:packed_ice","minecraft:painting","minecraft:panda_spawn_egg","minecraft:paper","minecraft:parrot_spawn_egg","minecraft:peony","minecraft:petrified_oak_slab","minecraft:phantom_membrane","minecraft:phantom_spawn_egg","minecraft:pig_spawn_egg","minecraft:pillager_spawn_egg","minecraft:pink_banner","minecraft:pink_bed","minecraft:pink_carpet","minecraft:pink_concrete","minecraft:pink_concrete_powder","minecraft:pink_dye","minecraft:pink_glazed_terracotta","minecraft:pink_shulker_box","minecraft:pink_stained_glass","minecraft:pink_stained_glass_pane","minecraft:pink_terracotta","minecraft:pink_tulip","minecraft:pink_wool","minecraft:piston","minecraft:player_head","minecraft:podzol","minecraft:poisonous_potato","minecraft:polar_bear_spawn_egg","minecraft:polished_andesite","minecraft:polished_andesite_slab","minecraft:polished_andesite_stairs","minecraft:polished_diorite","minecraft:polished_diorite_slab","minecraft:polished_diorite_stairs","minecraft:polished_granite","minecraft:polished_granite_slab","minecraft:polished_granite_stairs","minecraft:popped_chorus_fruit","minecraft:poppy","minecraft:porkchop","minecraft:potato","minecraft:potion","minecraft:powered_rail","minecraft:prismarine","minecraft:prismarine_brick_slab","minecraft:prismarine_brick_stairs","minecraft:prismarine_bricks","minecraft:prismarine_crystals","minecraft:prismarine_shard","minecraft:prismarine_slab","minecraft:prismarine_stairs","minecraft:prismarine_wall","minecraft:pufferfish","minecraft:pufferfish_bucket","minecraft:pufferfish_spawn_egg","minecraft:pumpkin","minecraft:pumpkin_pie","minecraft:pumpkin_seeds","minecraft:purple_banner","minecraft:purple_bed","minecraft:purple_carpet","minecraft:purple_concrete","minecraft:purple_concrete_powder","minecraft:purple_dye","minecraft:purple_glazed_terracotta","minecraft:purple_shulker_box","minecraft:purple_stained_glass","minecraft:purple_stained_glass_pane","minecraft:purple_terracotta","minecraft:purple_wool","minecraft:purpur_block","minecraft:purpur_pillar","minecraft:purpur_slab","minecraft:purpur_stairs","minecraft:quartz","minecraft:quartz_block","minecraft:quartz_pillar","minecraft:quartz_slab","minecraft:quartz_stairs","minecraft:rabbit","minecraft:rabbit_foot","minecraft:rabbit_hide","minecraft:rabbit_spawn_egg","minecraft:rabbit_stew","minecraft:rail","minecraft:ravager_spawn_egg","minecraft:red_banner","minecraft:red_bed","minecraft:red_carpet","minecraft:red_concrete","minecraft:red_concrete_powder","minecraft:red_dye","minecraft:red_glazed_terracotta","minecraft:red_mushroom","minecraft:red_mushroom_block","minecraft:red_nether_brick_slab","minecraft:red_nether_brick_stairs","minecraft:red_nether_brick_wall","minecraft:red_nether_bricks","minecraft:red_sand","minecraft:red_sandstone","minecraft:red_sandstone_slab","minecraft:red_sandstone_stairs","minecraft:red_sandstone_wall","minecraft:red_shulker_box","minecraft:red_stained_glass","minecraft:red_stained_glass_pane","minecraft:red_terracotta","minecraft:red_tulip","minecraft:red_wool","minecraft:redstone","minecraft:redstone_block","minecraft:redstone_lamp","minecraft:redstone_ore","minecraft:redstone_torch","minecraft:repeater","minecraft:repeating_command_block","minecraft:rose_bush","minecraft:rotten_flesh","minecraft:saddle","minecraft:salmon","minecraft:salmon_bucket","minecraft:salmon_spawn_egg","minecraft:sand","minecraft:sandstone","minecraft:sandstone_slab","minecraft:sandstone_stairs","minecraft:sandstone_wall","minecraft:scaffolding","minecraft:scute","minecraft:sea_lantern","minecraft:sea_pickle","minecraft:seagrass","minecraft:shears","minecraft:sheep_spawn_egg","minecraft:shield","minecraft:shulker_box","minecraft:shulker_shell","minecraft:shulker_spawn_egg","minecraft:silverfish_spawn_egg","minecraft:skeleton_horse_spawn_egg","minecraft:skeleton_skull","minecraft:skeleton_spawn_egg","minecraft:skull_banner_pattern","minecraft:slime_ball","minecraft:slime_block","minecraft:slime_spawn_egg","minecraft:smithing_table","minecraft:smoker","minecraft:smooth_quartz","minecraft:smooth_quartz_slab","minecraft:smooth_quartz_stairs","minecraft:smooth_red_sandstone","minecraft:smooth_red_sandstone_slab","minecraft:smooth_red_sandstone_stairs","minecraft:smooth_sandstone","minecraft:smooth_sandstone_slab","minecraft:smooth_sandstone_stairs","minecraft:smooth_stone","minecraft:smooth_stone_slab","minecraft:snow","minecraft:snow_block","minecraft:snowball","minecraft:soul_sand","minecraft:spawner","minecraft:spectral_arrow","minecraft:spider_eye","minecraft:spider_spawn_egg","minecraft:splash_potion","minecraft:sponge","minecraft:spruce_boat","minecraft:spruce_button","minecraft:spruce_door","minecraft:spruce_fence","minecraft:spruce_fence_gate","minecraft:spruce_leaves","minecraft:spruce_log","minecraft:spruce_planks","minecraft:spruce_pressure_plate","minecraft:spruce_sapling","minecraft:spruce_sign","minecraft:spruce_slab","minecraft:spruce_stairs","minecraft:spruce_trapdoor","minecraft:spruce_wood","minecraft:squid_spawn_egg","minecraft:stick","minecraft:sticky_piston","minecraft:stone","minecraft:stone_axe","minecraft:stone_brick_slab","minecraft:stone_brick_stairs","minecraft:stone_brick_wall","minecraft:stone_bricks","minecraft:stone_button","minecraft:stone_hoe","minecraft:stone_pickaxe","minecraft:stone_pressure_plate","minecraft:stone_shovel","minecraft:stone_slab","minecraft:stone_stairs","minecraft:stone_sword","minecraft:stonecutter","minecraft:stray_spawn_egg","minecraft:string","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood","minecraft:structure_block","minecraft:structure_void","minecraft:sugar","minecraft:sugar_cane","minecraft:sunflower","minecraft:suspicious_stew","minecraft:sweet_berries","minecraft:tall_grass","minecraft:terracotta","minecraft:tipped_arrow","minecraft:tnt","minecraft:tnt_minecart","minecraft:torch","minecraft:totem_of_undying","minecraft:trader_llama_spawn_egg","minecraft:trapped_chest","minecraft:trident","minecraft:tripwire_hook","minecraft:tropical_fish","minecraft:tropical_fish_bucket","minecraft:tropical_fish_spawn_egg","minecraft:tube_coral","minecraft:tube_coral_block","minecraft:tube_coral_fan","minecraft:turtle_egg","minecraft:turtle_helmet","minecraft:turtle_spawn_egg","minecraft:vex_spawn_egg","minecraft:villager_spawn_egg","minecraft:vindicator_spawn_egg","minecraft:vine","minecraft:wandering_trader_spawn_egg","minecraft:water_bucket","minecraft:wet_sponge","minecraft:wheat","minecraft:wheat_seeds","minecraft:white_banner","minecraft:white_bed","minecraft:white_carpet","minecraft:white_concrete","minecraft:white_concrete_powder","minecraft:white_dye","minecraft:white_glazed_terracotta","minecraft:white_shulker_box","minecraft:white_stained_glass","minecraft:white_stained_glass_pane","minecraft:white_terracotta","minecraft:white_tulip","minecraft:white_wool","minecraft:witch_spawn_egg","minecraft:wither_rose","minecraft:wither_skeleton_skull","minecraft:wither_skeleton_spawn_egg","minecraft:wolf_spawn_egg","minecraft:wooden_axe","minecraft:wooden_hoe","minecraft:wooden_pickaxe","minecraft:wooden_shovel","minecraft:wooden_sword","minecraft:writable_book","minecraft:written_book","minecraft:yellow_banner","minecraft:yellow_bed","minecraft:yellow_carpet","minecraft:yellow_concrete","minecraft:yellow_concrete_powder","minecraft:yellow_dye","minecraft:yellow_glazed_terracotta","minecraft:yellow_shulker_box","minecraft:yellow_stained_glass","minecraft:yellow_stained_glass_pane","minecraft:yellow_terracotta","minecraft:yellow_wool","minecraft:zombie_head","minecraft:zombie_horse_spawn_egg","minecraft:zombie_pigman_spawn_egg","minecraft:zombie_spawn_egg","minecraft:zombie_villager_spawn_egg"],"entities":["minecraft:area_effect_cloud","minecraft:armor_stand","minecraft:arrow","minecraft:bat","minecraft:blaze","minecraft:boat","minecraft:cat","minecraft:cave_spider","minecraft:chest_minecart","minecraft:chicken","minecraft:cod","minecraft:command_block_minecart","minecraft:cow","minecraft:creeper","minecraft:dolphin","minecraft:donkey","minecraft:dragon_fireball","minecraft:drowned","minecraft:egg","minecraft:elder_guardian","minecraft:end_crystal","minecraft:ender_dragon","minecraft:ender_pearl","minecraft:enderman","minecraft:endermite","minecraft:evoker","minecraft:evoker_fangs","minecraft:experience_bottle","minecraft:experience_orb","minecraft:eye_of_ender","minecraft:falling_block","minecraft:fireball","minecraft:firework_rocket","minecraft:fishing_bobber","minecraft:fox","minecraft:furnace_minecart","minecraft:ghast","minecraft:giant","minecraft:guardian","minecraft:hopper_minecart","minecraft:horse","minecraft:husk","minecraft:illusioner","minecraft:iron_golem","minecraft:item","minecraft:item_frame","minecraft:leash_knot","minecraft:lightning_bolt","minecraft:llama","minecraft:llama_spit","minecraft:magma_cube","minecraft:minecart","minecraft:mooshroom","minecraft:mule","minecraft:ocelot","minecraft:painting","minecraft:panda","minecraft:parrot","minecraft:phantom","minecraft:pig","minecraft:pillager","minecraft:player","minecraft:polar_bear","minecraft:potion","minecraft:pufferfish","minecraft:rabbit","minecraft:ravager","minecraft:salmon","minecraft:sheep","minecraft:shulker","minecraft:shulker_bullet","minecraft:silverfish","minecraft:skeleton","minecraft:skeleton_horse","minecraft:slime","minecraft:small_fireball","minecraft:snow_golem","minecraft:snowball","minecraft:spawner_minecart","minecraft:spectral_arrow","minecraft:spider","minecraft:squid","minecraft:stray","minecraft:tnt","minecraft:tnt_minecart","minecraft:trader_llama","minecraft:trident","minecraft:tropical_fish","minecraft:turtle","minecraft:vex","minecraft:villager","minecraft:vindicator","minecraft:wandering_trader","minecraft:witch","minecraft:wither","minecraft:wither_skeleton","minecraft:wither_skull","minecraft:wolf","minecraft:zombie","minecraft:zombie_horse","minecraft:zombie_pigman","minecraft:zombie_villager"],"biomes":["minecraft:badlands","minecraft:badlands_plateau","minecraft:bamboo_jungle","minecraft:bamboo_jungle_hills","minecraft:beach","minecraft:birch_forest","minecraft:birch_forest_hills","minecraft:cold_ocean","minecraft:dark_forest","minecraft:dark_forest_hills","minecraft:deep_cold_ocean","minecraft:deep_frozen_ocean","minecraft:deep_lukewarm_ocean","minecraft:deep_ocean","minecraft:deep_warm_ocean","minecraft:desert","minecraft:desert_hills","minecraft:desert_lakes","minecraft:end_barrens","minecraft:end_highlands","minecraft:end_midlands","minecraft:eroded_badlands","minecraft:flower_forest","minecraft:forest","minecraft:frozen_ocean","minecraft:frozen_river","minecraft:giant_spruce_taiga","minecraft:giant_spruce_taiga_hills","minecraft:giant_tree_taiga","minecraft:giant_tree_taiga_hills","minecraft:gravelly_mountains","minecraft:ice_spikes","minecraft:jungle","minecraft:jungle_edge","minecraft:jungle_hills","minecraft:lukewarm_ocean","minecraft:modified_badlands_plateau","minecraft:modified_gravelly_mountains","minecraft:modified_jungle","minecraft:modified_jungle_edge","minecraft:modified_wooded_badlands_plateau","minecraft:mountain_edge","minecraft:mountains","minecraft:mushroom_field_shore","minecraft:mushroom_fields","minecraft:nether","minecraft:ocean","minecraft:plains","minecraft:river","minecraft:savanna","minecraft:savanna_plateau","minecraft:shattered_savanna","minecraft:shattered_savanna_plateau","minecraft:small_end_islands","minecraft:snowy_beach","minecraft:snowy_mountains","minecraft:snowy_taiga","minecraft:snowy_taiga_hills","minecraft:snowy_taiga_mountains","minecraft:snowy_tundra","minecraft:stone_shore","minecraft:sunflower_plains","minecraft:swamp","minecraft:swamp_hills","minecraft:taiga","minecraft:taiga_hills","minecraft:taiga_mountains","minecraft:tall_birch_forest","minecraft:tall_birch_hills","minecraft:the_end","minecraft:the_void","minecraft:warm_ocean","minecraft:wooded_badlands_plateau","minecraft:wooded_hills","minecraft:wooded_mountains"],"blocktags":{"minecraft:slabs":["minecraft:stone_slab","minecraft:smooth_stone_slab","minecraft:stone_brick_slab","minecraft:sandstone_slab","minecraft:acacia_slab","minecraft:birch_slab","minecraft:dark_oak_slab","minecraft:jungle_slab","minecraft:oak_slab","minecraft:spruce_slab","minecraft:purpur_slab","minecraft:quartz_slab","minecraft:red_sandstone_slab","minecraft:brick_slab","minecraft:cobblestone_slab","minecraft:nether_brick_slab","minecraft:petrified_oak_slab","minecraft:prismarine_slab","minecraft:prismarine_brick_slab","minecraft:dark_prismarine_slab","minecraft:polished_granite_slab","minecraft:smooth_red_sandstone_slab","minecraft:mossy_stone_brick_slab","minecraft:polished_diorite_slab","minecraft:mossy_cobblestone_slab","minecraft:end_stone_brick_slab","minecraft:smooth_sandstone_slab","minecraft:smooth_quartz_slab","minecraft:granite_slab","minecraft:andesite_slab","minecraft:red_nether_brick_slab","minecraft:polished_andesite_slab","minecraft:diorite_slab","minecraft:cut_sandstone_slab","minecraft:cut_red_sandstone_slab"],"minecraft:carpets":["minecraft:white_carpet","minecraft:orange_carpet","minecraft:magenta_carpet","minecraft:light_blue_carpet","minecraft:yellow_carpet","minecraft:lime_carpet","minecraft:pink_carpet","minecraft:gray_carpet","minecraft:light_gray_carpet","minecraft:cyan_carpet","minecraft:purple_carpet","minecraft:blue_carpet","minecraft:brown_carpet","minecraft:green_carpet","minecraft:red_carpet","minecraft:black_carpet"],"minecraft:stairs":["minecraft:oak_stairs","minecraft:cobblestone_stairs","minecraft:spruce_stairs","minecraft:sandstone_stairs","minecraft:acacia_stairs","minecraft:jungle_stairs","minecraft:birch_stairs","minecraft:dark_oak_stairs","minecraft:nether_brick_stairs","minecraft:stone_brick_stairs","minecraft:brick_stairs","minecraft:purpur_stairs","minecraft:quartz_stairs","minecraft:red_sandstone_stairs","minecraft:prismarine_brick_stairs","minecraft:prismarine_stairs","minecraft:dark_prismarine_stairs","minecraft:polished_granite_stairs","minecraft:smooth_red_sandstone_stairs","minecraft:mossy_stone_brick_stairs","minecraft:polished_diorite_stairs","minecraft:mossy_cobblestone_stairs","minecraft:end_stone_brick_stairs","minecraft:stone_stairs","minecraft:smooth_sandstone_stairs","minecraft:smooth_quartz_stairs","minecraft:granite_stairs","minecraft:andesite_stairs","minecraft:red_nether_brick_stairs","minecraft:polished_andesite_stairs","minecraft:diorite_stairs"],"minecraft:wooden_doors":["minecraft:oak_door","minecraft:spruce_door","minecraft:birch_door","minecraft:jungle_door","minecraft:acacia_door","minecraft:dark_oak_door"],"minecraft:jungle_logs":["minecraft:jungle_log","minecraft:jungle_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood"],"minecraft:planks":["minecraft:oak_planks","minecraft:spruce_planks","minecraft:birch_planks","minecraft:jungle_planks","minecraft:acacia_planks","minecraft:dark_oak_planks"],"minecraft:wall_corals":["minecraft:tube_coral_wall_fan","minecraft:brain_coral_wall_fan","minecraft:bubble_coral_wall_fan","minecraft:fire_coral_wall_fan","minecraft:horn_coral_wall_fan"],"minecraft:acacia_logs":["minecraft:acacia_log","minecraft:acacia_wood","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood"],"minecraft:wither_immune":["minecraft:barrier","minecraft:bedrock","minecraft:end_portal","minecraft:end_portal_frame","minecraft:end_gateway","minecraft:command_block","minecraft:repeating_command_block","minecraft:chain_command_block","minecraft:structure_block","minecraft:jigsaw","minecraft:moving_piston"],"minecraft:flower_pots":["minecraft:flower_pot","minecraft:potted_poppy","minecraft:potted_blue_orchid","minecraft:potted_allium","minecraft:potted_azure_bluet","minecraft:potted_red_tulip","minecraft:potted_orange_tulip","minecraft:potted_white_tulip","minecraft:potted_pink_tulip","minecraft:potted_oxeye_daisy","minecraft:potted_dandelion","minecraft:potted_oak_sapling","minecraft:potted_spruce_sapling","minecraft:potted_birch_sapling","minecraft:potted_jungle_sapling","minecraft:potted_acacia_sapling","minecraft:potted_dark_oak_sapling","minecraft:potted_red_mushroom","minecraft:potted_brown_mushroom","minecraft:potted_dead_bush","minecraft:potted_fern","minecraft:potted_cactus","minecraft:potted_cornflower","minecraft:potted_lily_of_the_valley","minecraft:potted_wither_rose","minecraft:potted_bamboo"],"minecraft:stone_bricks":["minecraft:stone_bricks","minecraft:mossy_stone_bricks","minecraft:cracked_stone_bricks","minecraft:chiseled_stone_bricks"],"minecraft:enderman_holdable":["minecraft:grass_block","minecraft:dirt","minecraft:coarse_dirt","minecraft:podzol","minecraft:sand","minecraft:red_sand","minecraft:gravel","minecraft:brown_mushroom","minecraft:red_mushroom","minecraft:tnt","minecraft:cactus","minecraft:clay","minecraft:pumpkin","minecraft:carved_pumpkin","minecraft:melon","minecraft:mycelium","minecraft:netherrack","minecraft:dandelion","minecraft:poppy","minecraft:blue_orchid","minecraft:allium","minecraft:azure_bluet","minecraft:red_tulip","minecraft:orange_tulip","minecraft:white_tulip","minecraft:pink_tulip","minecraft:oxeye_daisy","minecraft:cornflower","minecraft:lily_of_the_valley","minecraft:wither_rose"],"minecraft:spruce_logs":["minecraft:spruce_log","minecraft:spruce_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood"],"minecraft:wooden_slabs":["minecraft:oak_slab","minecraft:spruce_slab","minecraft:birch_slab","minecraft:jungle_slab","minecraft:acacia_slab","minecraft:dark_oak_slab"],"minecraft:coral_blocks":["minecraft:tube_coral_block","minecraft:brain_coral_block","minecraft:bubble_coral_block","minecraft:fire_coral_block","minecraft:horn_coral_block"],"minecraft:signs":["minecraft:oak_sign","minecraft:spruce_sign","minecraft:birch_sign","minecraft:acacia_sign","minecraft:jungle_sign","minecraft:dark_oak_sign","minecraft:oak_wall_sign","minecraft:spruce_wall_sign","minecraft:birch_wall_sign","minecraft:acacia_wall_sign","minecraft:jungle_wall_sign","minecraft:dark_oak_wall_sign"],"minecraft:dark_oak_logs":["minecraft:dark_oak_log","minecraft:dark_oak_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood"],"minecraft:sand":["minecraft:sand","minecraft:red_sand"],"minecraft:valid_spawn":["minecraft:grass_block","minecraft:podzol"],"minecraft:underwater_bonemeals":["minecraft:seagrass","minecraft:tube_coral_fan","minecraft:brain_coral_fan","minecraft:bubble_coral_fan","minecraft:fire_coral_fan","minecraft:horn_coral_fan","minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral","minecraft:tube_coral_wall_fan","minecraft:brain_coral_wall_fan","minecraft:bubble_coral_wall_fan","minecraft:fire_coral_wall_fan","minecraft:horn_coral_wall_fan"],"minecraft:oak_logs":["minecraft:oak_log","minecraft:oak_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood"],"minecraft:buttons":["minecraft:stone_button","minecraft:oak_button","minecraft:spruce_button","minecraft:birch_button","minecraft:jungle_button","minecraft:acacia_button","minecraft:dark_oak_button"],"minecraft:wooden_pressure_plates":["minecraft:oak_pressure_plate","minecraft:spruce_pressure_plate","minecraft:birch_pressure_plate","minecraft:jungle_pressure_plate","minecraft:acacia_pressure_plate","minecraft:dark_oak_pressure_plate"],"minecraft:beds":["minecraft:red_bed","minecraft:black_bed","minecraft:blue_bed","minecraft:brown_bed","minecraft:cyan_bed","minecraft:gray_bed","minecraft:green_bed","minecraft:light_blue_bed","minecraft:light_gray_bed","minecraft:lime_bed","minecraft:magenta_bed","minecraft:orange_bed","minecraft:pink_bed","minecraft:purple_bed","minecraft:white_bed","minecraft:yellow_bed"],"minecraft:walls":["minecraft:cobblestone_wall","minecraft:mossy_cobblestone_wall","minecraft:brick_wall","minecraft:prismarine_wall","minecraft:red_sandstone_wall","minecraft:mossy_stone_brick_wall","minecraft:granite_wall","minecraft:stone_brick_wall","minecraft:nether_brick_wall","minecraft:andesite_wall","minecraft:red_nether_brick_wall","minecraft:sandstone_wall","minecraft:end_stone_brick_wall","minecraft:diorite_wall"],"minecraft:rails":["minecraft:rail","minecraft:powered_rail","minecraft:detector_rail","minecraft:activator_rail"],"minecraft:birch_logs":["minecraft:birch_log","minecraft:birch_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood"],"minecraft:wooden_trapdoors":["minecraft:acacia_trapdoor","minecraft:birch_trapdoor","minecraft:dark_oak_trapdoor","minecraft:jungle_trapdoor","minecraft:oak_trapdoor","minecraft:spruce_trapdoor"],"minecraft:wooden_fences":["minecraft:oak_fence","minecraft:acacia_fence","minecraft:dark_oak_fence","minecraft:spruce_fence","minecraft:birch_fence","minecraft:jungle_fence"],"minecraft:saplings":["minecraft:oak_sapling","minecraft:spruce_sapling","minecraft:birch_sapling","minecraft:jungle_sapling","minecraft:acacia_sapling","minecraft:dark_oak_sapling"],"minecraft:small_flowers":["minecraft:dandelion","minecraft:poppy","minecraft:blue_orchid","minecraft:allium","minecraft:azure_bluet","minecraft:red_tulip","minecraft:orange_tulip","minecraft:white_tulip","minecraft:pink_tulip","minecraft:oxeye_daisy","minecraft:cornflower","minecraft:lily_of_the_valley","minecraft:wither_rose"],"minecraft:bamboo_plantable_on":["minecraft:bamboo","minecraft:bamboo_sapling","minecraft:gravel","minecraft:sand","minecraft:red_sand","minecraft:dirt","minecraft:grass_block","minecraft:podzol","minecraft:coarse_dirt","minecraft:mycelium"],"minecraft:ice":["minecraft:ice","minecraft:packed_ice","minecraft:blue_ice","minecraft:frosted_ice"],"minecraft:wooden_stairs":["minecraft:oak_stairs","minecraft:spruce_stairs","minecraft:birch_stairs","minecraft:jungle_stairs","minecraft:acacia_stairs","minecraft:dark_oak_stairs"],"minecraft:anvil":["minecraft:anvil","minecraft:chipped_anvil","minecraft:damaged_anvil"],"minecraft:logs":["minecraft:dark_oak_log","minecraft:dark_oak_wood","minecraft:stripped_dark_oak_log","minecraft:stripped_dark_oak_wood","minecraft:oak_log","minecraft:oak_wood","minecraft:stripped_oak_log","minecraft:stripped_oak_wood","minecraft:acacia_log","minecraft:acacia_wood","minecraft:stripped_acacia_log","minecraft:stripped_acacia_wood","minecraft:birch_log","minecraft:birch_wood","minecraft:stripped_birch_log","minecraft:stripped_birch_wood","minecraft:jungle_log","minecraft:jungle_wood","minecraft:stripped_jungle_log","minecraft:stripped_jungle_wood","minecraft:spruce_log","minecraft:spruce_wood","minecraft:stripped_spruce_log","minecraft:stripped_spruce_wood"],"minecraft:corals":["minecraft:tube_coral_fan","minecraft:brain_coral_fan","minecraft:bubble_coral_fan","minecraft:fire_coral_fan","minecraft:horn_coral_fan","minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral"],"minecraft:wooden_buttons":["minecraft:oak_button","minecraft:spruce_button","minecraft:birch_button","minecraft:jungle_button","minecraft:acacia_button","minecraft:dark_oak_button"],"minecraft:wool":["minecraft:white_wool","minecraft:orange_wool","minecraft:magenta_wool","minecraft:light_blue_wool","minecraft:yellow_wool","minecraft:lime_wool","minecraft:pink_wool","minecraft:gray_wool","minecraft:light_gray_wool","minecraft:cyan_wool","minecraft:purple_wool","minecraft:blue_wool","minecraft:brown_wool","minecraft:green_wool","minecraft:red_wool","minecraft:black_wool"],"minecraft:coral_plants":["minecraft:tube_coral","minecraft:brain_coral","minecraft:bubble_coral","minecraft:fire_coral","minecraft:horn_coral"],"minecraft:banners":["minecraft:white_banner","minecraft:orange_banner","minecraft:magenta_banner","minecraft:light_blue_banner","minecraft:yellow_banner","minecraft:lime_banner","minecraft:pink_banner","minecraft:gray_banner","minecraft:light_gray_banner","minecraft:cyan_banner","minecraft:purple_banner","minecraft:blue_banner","minecraft:brown_banner","minecraft:green_banner","minecraft:red_banner","minecraft:black_banner","minecraft:white_wall_banner","minecraft:orange_wall_banner","minecraft:magenta_wall_banner","minecraft:light_blue_wall_banner","minecraft:yellow_wall_banner","minecraft:lime_wall_banner","minecraft:pink_wall_banner","minecraft:gray_wall_banner","minecraft:light_gray_wall_banner","minecraft:cyan_wall_banner","minecraft:purple_wall_banner","minecraft:blue_wall_banner","minecraft:brown_wall_banner","minecraft:green_wall_banner","minecraft:red_wall_banner","minecraft:black_wall_banner"],"minecraft:dragon_immune":["minecraft:barrier","minecraft:bedrock","minecraft:end_portal","minecraft:end_portal_frame","minecraft:end_gateway","minecraft:command_block","minecraft:repeating_command_block","minecraft:chain_command_block","minecraft:structure_block","minecraft:jigsaw","minecraft:moving_piston","minecraft:obsidian","minecraft:end_stone","minecraft:iron_bars"],"minecraft:doors":["minecraft:iron_door","minecraft:oak_door","minecraft:spruce_door","minecraft:birch_door","minecraft:jungle_door","minecraft:acacia_door","minecraft:dark_oak_door"],"minecraft:fences":["minecraft:nether_brick_fence","minecraft:oak_fence","minecraft:acacia_fence","minecraft:dark_oak_fence","minecraft:spruce_fence","minecraft:birch_fence","minecraft:jungle_fence"],"minecraft:wall_signs":["minecraft:oak_wall_sign","minecraft:spruce_wall_sign","minecraft:birch_wall_sign","minecraft:acacia_wall_sign","minecraft:jungle_wall_sign","minecraft:dark_oak_wall_sign"],"minecraft:standing_signs":["minecraft:oak_sign","minecraft:spruce_sign","minecraft:birch_sign","minecraft:acacia_sign","minecraft:jungle_sign","minecraft:dark_oak_sign"],"minecraft:dirt_like":["minecraft:dirt","minecraft:grass_block","minecraft:podzol","minecraft:coarse_dirt","minecraft:mycelium"],"minecraft:impermeable":["minecraft:glass","minecraft:white_stained_glass","minecraft:orange_stained_glass","minecraft:magenta_stained_glass","minecraft:light_blue_stained_glass","minecraft:yellow_stained_glass","minecraft:lime_stained_glass","minecraft:pink_stained_glass","minecraft:gray_stained_glass","minecraft:light_gray_stained_glass","minecraft:cyan_stained_glass","minecraft:purple_stained_glass","minecraft:blue_stained_glass","minecraft:brown_stained_glass","minecraft:green_stained_glass","minecraft:red_stained_glass","minecraft:black_stained_glass"],"minecraft:trapdoors":["minecraft:iron_trapdoor","minecraft:acacia_trapdoor","minecraft:birch_trapdoor","minecraft:dark_oak_trapdoor","minecraft:jungle_trapdoor","minecraft:oak_trapdoor","minecraft:spruce_trapdoor"],"minecraft:leaves":["minecraft:jungle_leaves","minecraft:oak_leaves","minecraft:spruce_leaves","minecraft:dark_oak_leaves","minecraft:acacia_leaves","minecraft:birch_leaves"]},"itemtags":{"minecraft:boats":["minecraft:oak_boat","minecraft:spruce_boat","minecraft:birch_boat","minecraft:jungle_boat","minecraft:acacia_boat","minecraft:dark_oak_boat"],"minecraft:banners":["minecraft:white_banner","minecraft:orange_banner","minecraft:magenta_banner","minecraft:light_blue_banner","minecraft:yellow_banner","minecraft:lime_banner","minecraft:pink_banner","minecraft:gray_banner","minecraft:light_gray_banner","minecraft:cyan_banner","minecraft:purple_banner","minecraft:blue_banner","minecraft:brown_banner","minecraft:green_banner","minecraft:red_banner","minecraft:black_banner"],"minecraft:arrows":["minecraft:arrow","minecraft:tipped_arrow","minecraft:spectral_arrow"],"minecraft:coals":["minecraft:coal","minecraft:charcoal"],"minecraft:music_discs":["minecraft:music_disc_13","minecraft:music_disc_cat","minecraft:music_disc_blocks","minecraft:music_disc_chirp","minecraft:music_disc_far","minecraft:music_disc_mall","minecraft:music_disc_mellohi","minecraft:music_disc_stal","minecraft:music_disc_strad","minecraft:music_disc_ward","minecraft:music_disc_11","minecraft:music_disc_wait"],"minecraft:fishes":["minecraft:cod","minecraft:cooked_cod","minecraft:salmon","minecraft:cooked_salmon","minecraft:pufferfish","minecraft:tropical_fish"]},"entitytags":{"minecraft:raiders":["minecraft:evoker","minecraft:pillager","minecraft:ravager","minecraft:vindicator","minecraft:illusioner","minecraft:witch"],"minecraft:skeletons":["minecraft:skeleton","minecraft:stray","minecraft:wither_skeleton"]}} \ No newline at end of file diff --git a/worldedit-cli/src/main/resources/defaults/worldedit.properties b/worldedit-cli/src/main/resources/defaults/worldedit.properties new file mode 100644 index 000000000..d0296c15c --- /dev/null +++ b/worldedit-cli/src/main/resources/defaults/worldedit.properties @@ -0,0 +1,33 @@ +#Don't put comments; they get removed +default-max-polygon-points=-1 +schematic-save-dir=schematics +super-pickaxe-many-drop-items=true +register-help=true +nav-wand-item=minecraft:compass +profile=false +trace-unflushed-sessions=false +super-pickaxe-drop-items=true +disallowed-blocks=minecraft:oak_sapling,minecraft:jungle_sapling,minecraft:dark_oak_sapling,minecraft:spruce_sapling,minecraft:birch_sapling,minecraft:acacia_sapling,minecraft:black_bed,minecraft:blue_bed,minecraft:brown_bed,minecraft:cyan_bed,minecraft:gray_bed,minecraft:green_bed,minecraft:light_blue_bed,minecraft:light_gray_bed,minecraft:lime_bed,minecraft:magenta_bed,minecraft:orange_bed,minecraft:pink_bed,minecraft:purple_bed,minecraft:red_bed,minecraft:white_bed,minecraft:yellow_bed,minecraft:powered_rail,minecraft:detector_rail,minecraft:grass,minecraft:dead_bush,minecraft:moving_piston,minecraft:piston_head,minecraft:sunflower,minecraft:rose_bush,minecraft:dandelion,minecraft:poppy,minecraft:brown_mushroom,minecraft:red_mushroom,minecraft:tnt,minecraft:torch,minecraft:fire,minecraft:redstone_wire,minecraft:wheat,minecraft:potatoes,minecraft:carrots,minecraft:melon_stem,minecraft:pumpkin_stem,minecraft:beetroots,minecraft:rail,minecraft:lever,minecraft:redstone_torch,minecraft:redstone_wall_torch,minecraft:repeater,minecraft:comparator,minecraft:stone_button,minecraft:birch_button,minecraft:acacia_button,minecraft:dark_oak_button,minecraft:jungle_button,minecraft:oak_button,minecraft:spruce_button,minecraft:cactus,minecraft:sugar_cane,minecraft:bedrock +max-super-pickaxe-size=5 +max-brush-radius=10 +craftscript-dir=craftscripts +no-double-slash=false +wand-item=minecraft:wooden_axe +shell-save-type= +scripting-timeout=3000 +snapshots-dir= +use-inventory-creative-override=false +log-file=worldedit.log +log-format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s]: %5$s%6$s%n +max-changed-blocks=-1 +nav-wand-distance=50 +butcher-default-radius=-1 +default-max-changed-blocks=-1 +history-size=15 +use-inventory=false +allow-symbolic-links=false +use-inventory-override=false +log-commands=false +butcher-max-radius=-1 +max-polygon-points=20 +max-radius=-1 diff --git a/worldedit-cli/src/main/resources/log4j2.xml b/worldedit-cli/src/main/resources/log4j2.xml new file mode 100644 index 000000000..9642c1b7d --- /dev/null +++ b/worldedit-cli/src/main/resources/log4j2.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java index 9b288271f..88b22bf1b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionFactory.java @@ -21,8 +21,8 @@ package com.sk89q.worldedit; import static com.google.common.base.Preconditions.checkNotNull; -import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.world.World; @@ -65,10 +65,10 @@ public class EditSessionFactory { * * @param world the world * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit - * @param player the player that the {@link EditSession} is for + * @param actor the actor that the {@link EditSession} is for * @return an instance */ - public EditSession getEditSession(World world, int maxBlocks, Player player) { + public EditSession getEditSession(World world, int maxBlocks, Actor actor) { // ============ READ ME ============ @@ -114,10 +114,10 @@ public class EditSessionFactory { * @param world the world * @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit * @param blockBag an optional {@link BlockBag} to use, otherwise null - * @param player the player that the {@link EditSession} is for + * @param actor the actor that the {@link EditSession} is for * @return an instance */ - public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Player player) { + public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Actor actor) { // ============ READ ME ============ @@ -156,8 +156,8 @@ public class EditSessionFactory { } @Override - public EditSession getEditSession(World world, int maxBlocks, Player player) { - return getEditSession(world, maxBlocks, null, player); + public EditSession getEditSession(World world, int maxBlocks, Actor actor) { + return getEditSession(world, maxBlocks, null, actor); } @Override @@ -166,11 +166,11 @@ public class EditSessionFactory { } @Override - public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Player player) { + public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Actor actor) { if (WorldEdit.getInstance().getConfiguration().traceUnflushedSessions) { - return new TracedEditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, player, maxBlocks, null)); + return new TracedEditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, actor, maxBlocks, null)); } - return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, player, maxBlocks, null)); + return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, actor, maxBlocks, null)); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 124b8661a..0b85b6cd2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.command.tool.SinglePickaxe; import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.internal.cui.CUIEvent; @@ -100,6 +101,7 @@ public class LocalSession { private transient BlockVector3 cuiTemporaryBlock; private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE; private transient List> lastDistribution; + private transient World worldOverride; // Saved properties private String lastScript; @@ -226,21 +228,21 @@ public class LocalSession { * Performs an undo. * * @param newBlockBag a new block bag - * @param player the player + * @param actor the actor * @return whether anything was undone */ - public EditSession undo(@Nullable BlockBag newBlockBag, Player player) { - checkNotNull(player); + public EditSession undo(@Nullable BlockBag newBlockBag, Actor actor) { + checkNotNull(actor); --historyPointer; if (historyPointer >= 0) { EditSession editSession = history.get(historyPointer); try (EditSession newEditSession = WorldEdit.getInstance().getEditSessionFactory() - .getEditSession(editSession.getWorld(), -1, newBlockBag, player)) { + .getEditSession(editSession.getWorld(), -1, newBlockBag, actor)) { newEditSession.enableStandardMode(); newEditSession.setReorderMode(reorderMode); newEditSession.setFastMode(fastMode); if (newEditSession.getSurvivalExtent() != null) { - newEditSession.getSurvivalExtent().setStripNbt(!player.hasPermission("worldedit.setnbt")); + newEditSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); } editSession.undo(newEditSession); } @@ -255,20 +257,20 @@ public class LocalSession { * Performs a redo * * @param newBlockBag a new block bag - * @param player the player + * @param actor the actor * @return whether anything was redone */ - public EditSession redo(@Nullable BlockBag newBlockBag, Player player) { - checkNotNull(player); + public EditSession redo(@Nullable BlockBag newBlockBag, Actor actor) { + checkNotNull(actor); if (historyPointer < history.size()) { EditSession editSession = history.get(historyPointer); try (EditSession newEditSession = WorldEdit.getInstance().getEditSessionFactory() - .getEditSession(editSession.getWorld(), -1, newBlockBag, player)) { + .getEditSession(editSession.getWorld(), -1, newBlockBag, actor)) { newEditSession.enableStandardMode(); newEditSession.setReorderMode(reorderMode); newEditSession.setFastMode(fastMode); if (newEditSession.getSurvivalExtent() != null) { - newEditSession.getSurvivalExtent().setStripNbt(!player.hasPermission("worldedit.setnbt")); + newEditSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); } editSession.redo(newEditSession); } @@ -279,6 +281,19 @@ public class LocalSession { return null; } + public boolean hasWorldOverride() { + return this.worldOverride != null; + } + + @Nullable + public World getWorldOverride() { + return this.worldOverride; + } + + public void setWorldOverride(@Nullable World worldOverride) { + this.worldOverride = worldOverride; + } + /** * Get the default region selector. * @@ -311,6 +326,9 @@ public class LocalSession { if (selector.getWorld() == null || !selector.getWorld().equals(world)) { selector.setWorld(world); selector.clear(); + if (hasWorldOverride() && !world.equals(getWorldOverride())) { + setWorldOverride(null); + } } return selector; } @@ -326,6 +344,9 @@ public class LocalSession { checkNotNull(selector); selector.setWorld(world); this.selector = selector; + if (hasWorldOverride() && !world.equals(getWorldOverride())) { + setWorldOverride(null); + } } /** @@ -483,14 +504,18 @@ public class LocalSession { * Get the position use for commands that take a center point * (i.e. //forestgen, etc.). * - * @param player the player + * @param actor the actor * @return the position to use * @throws IncompleteRegionException thrown if a region is not fully selected */ - public BlockVector3 getPlacementPosition(Player player) throws IncompleteRegionException { - checkNotNull(player); + public BlockVector3 getPlacementPosition(Actor actor) throws IncompleteRegionException { + checkNotNull(actor); if (!placeAtPos1) { - return player.getBlockIn().toVector().toBlockPoint(); + if (actor instanceof Locatable) { + return ((Locatable) actor).getBlockLocation().toVector().toBlockPoint(); + } else { + throw new IncompleteRegionException(); + } } return selector.getPrimaryPosition(); @@ -653,9 +678,9 @@ public class LocalSession { /** * Tell the player the WorldEdit version. * - * @param player the player + * @param actor the actor */ - public void tellVersion(Actor player) { + public void tellVersion(Actor actor) { } public boolean shouldUseServerCUI() { @@ -885,25 +910,38 @@ public class LocalSession { /** * Construct a new edit session. * - * @param player the player + * @param actor the actor * @return an edit session */ - public EditSession createEditSession(Player player) { - checkNotNull(player); + public EditSession createEditSession(Actor actor) { + checkNotNull(actor); - BlockBag blockBag = getBlockBag(player); + World world = null; + if (hasWorldOverride()) { + world = getWorldOverride(); + } else if (actor instanceof Locatable && ((Locatable) actor).getExtent() instanceof World) { + world = (World) ((Locatable) actor).getExtent(); + } // Create an edit session - EditSession editSession = WorldEdit.getInstance().getEditSessionFactory() - .getEditSession(player.isPlayer() ? player.getWorld() : null, - getBlockChangeLimit(), blockBag, player); + EditSession editSession; + if (actor.isPlayer() && actor instanceof Player) { + BlockBag blockBag = getBlockBag((Player) actor); + editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession( + world, + getBlockChangeLimit(), blockBag, actor + ); + } else { + editSession = WorldEdit.getInstance().getEditSessionFactory() + .getEditSession(world, getBlockChangeLimit()); + } Request.request().setEditSession(editSession); editSession.setFastMode(fastMode); editSession.setReorderMode(reorderMode); editSession.setMask(mask); if (editSession.getSurvivalExtent() != null) { - editSession.getSurvivalExtent().setStripNbt(!player.hasPermission("worldedit.setnbt")); + editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); } return editSession; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/MissingWorldException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/MissingWorldException.java new file mode 100644 index 000000000..fe6f6beaf --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/MissingWorldException.java @@ -0,0 +1,27 @@ +/* + * 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; + +/** + * Raised when a world is missing but is required. + */ +public class MissingWorldException extends WorldEditException { + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index db4d9e0a9..fade284c4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -229,7 +229,7 @@ public final class WorldEdit { * traversal exploits by checking the root directory and the file directory. * On success, a {@code java.io.File} object will be returned. * - * @param player the player + * @param actor the actor * @param dir sub-directory to look in * @param filename filename (user-submitted) * @param defaultExt append an extension if missing one, null to not use @@ -237,8 +237,8 @@ public final class WorldEdit { * @return a file * @throws FilenameException thrown if the filename is invalid */ - public File getSafeSaveFile(Player player, File dir, String filename, String defaultExt, String... extensions) throws FilenameException { - return getSafeFile(player, dir, filename, defaultExt, extensions, true); + public File getSafeSaveFile(Actor actor, File dir, String filename, String defaultExt, String... extensions) throws FilenameException { + return getSafeFile(actor, dir, filename, defaultExt, extensions, true); } /** @@ -247,7 +247,7 @@ public final class WorldEdit { * traversal exploits by checking the root directory and the file directory. * On success, a {@code java.io.File} object will be returned. * - * @param player the player + * @param actor the actor * @param dir sub-directory to look in * @param filename filename (user-submitted) * @param defaultExt append an extension if missing one, null to not use @@ -255,14 +255,14 @@ public final class WorldEdit { * @return a file * @throws FilenameException thrown if the filename is invalid */ - public File getSafeOpenFile(Player player, File dir, String filename, String defaultExt, String... extensions) throws FilenameException { - return getSafeFile(player, dir, filename, defaultExt, extensions, false); + public File getSafeOpenFile(Actor actor, File dir, String filename, String defaultExt, String... extensions) throws FilenameException { + return getSafeFile(actor, dir, filename, defaultExt, extensions, false); } /** * Get a safe path to a file. * - * @param player the player + * @param actor the actor * @param dir sub-directory to look in * @param filename filename (user-submitted) * @param defaultExt append an extension if missing one, null to not use @@ -271,16 +271,16 @@ public final class WorldEdit { * @return a file * @throws FilenameException thrown if the filename is invalid */ - private File getSafeFile(@Nullable Player player, File dir, String filename, String defaultExt, String[] extensions, boolean isSave) throws FilenameException { + private File getSafeFile(@Nullable Actor actor, File dir, String filename, String defaultExt, String[] extensions, boolean isSave) throws FilenameException { if (extensions != null && (extensions.length == 1 && extensions[0] == null)) extensions = null; File f; - if (filename.equals("#") && player != null) { + if (filename.equals("#") && actor != null) { if (isSave) { - f = player.openFileSaveDialog(extensions); + f = actor.openFileSaveDialog(extensions); } else { - f = player.openFileOpenDialog(extensions); + f = actor.openFileOpenDialog(extensions); } if (f == null) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java index 5d5d245d1..50d513a67 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ChunkCommands.java @@ -28,6 +28,7 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.anvil.ChunkDeleter; import com.sk89q.worldedit.internal.anvil.ChunkDeletionInfo; import com.sk89q.worldedit.math.BlockVector2; @@ -39,6 +40,7 @@ import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.storage.LegacyChunkStore; import com.sk89q.worldedit.world.storage.McRegionChunkStore; import org.enginehub.piston.annotation.Command; @@ -78,7 +80,7 @@ public class ChunkCommands { ) @CommandPermissions("worldedit.chunkinfo") public void chunkInfo(Player player) { - Location pos = player.getBlockIn(); + Location pos = player.getBlockLocation(); int chunkX = (int) Math.floor(pos.getBlockX() / 16.0); int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0); @@ -93,13 +95,13 @@ public class ChunkCommands { desc = "List chunks that your selection includes" ) @CommandPermissions("worldedit.listchunks") - public void listChunks(Player player, LocalSession session, + public void listChunks(Actor actor, World world, LocalSession session, @ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException { - final Region region = session.getSelection(player.getWorld()); + final Region region = session.getSelection(world); - WorldEditAsyncCommandBuilder.createAndSendMessage(player, + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> new ChunkListPaginationBox(region).create(page), - "Listing chunks for " + player.getName()); + "Listing chunks for " + actor.getName()); } @Command( @@ -108,10 +110,10 @@ public class ChunkCommands { ) @CommandPermissions("worldedit.delchunks") @Logging(REGION) - public void deleteChunks(Player player, LocalSession session, + public void deleteChunks(Actor actor, World world, LocalSession session, @ArgFlag(name = 'o', desc = "Only delete chunks older than the specified time.", def = "") ZonedDateTime beforeTime) throws WorldEditException { - Path worldDir = player.getWorld().getStoragePath(); + Path worldDir = world.getStoragePath(); if (worldDir == null) { throw new StopExecutionException(TextComponent.of("Couldn't find world folder for this world.")); } @@ -134,7 +136,7 @@ public class ChunkCommands { ChunkDeletionInfo.ChunkBatch newBatch = new ChunkDeletionInfo.ChunkBatch(); newBatch.worldPath = worldDir.toAbsolutePath().normalize().toString(); newBatch.backup = true; - final Region selection = session.getSelection(player.getWorld()); + final Region selection = session.getSelection(world); if (selection instanceof CuboidRegion) { newBatch.minChunk = selection.getMinimumPoint().shr(4).toBlockVector2(); newBatch.maxChunk = selection.getMaximumPoint().shr(4).toBlockVector2(); @@ -159,13 +161,13 @@ public class ChunkCommands { throw new StopExecutionException(TextComponent.of("Failed to write chunk list: " + e.getMessage())); } - player.print(String.format("%d chunk(s) have been marked for deletion the next time the server starts.", + actor.print(String.format("%d chunk(s) have been marked for deletion the next time the server starts.", newBatch.getChunkCount())); if (currentInfo.batches.size() > 1) { - player.printDebug(String.format("%d chunks total marked for deletion. (May have overlaps).", + actor.printDebug(String.format("%d chunks total marked for deletion. (May have overlaps).", currentInfo.batches.stream().mapToInt(ChunkDeletionInfo.ChunkBatch::getChunkCount).sum())); } - player.print(TextComponent.of("You can mark more chunks for deletion, or to stop now, run: ", TextColor.LIGHT_PURPLE) + actor.print(TextComponent.of("You can mark more chunks for deletion, or to stop now, run: ", TextColor.LIGHT_PURPLE) .append(TextComponent.of("/stop", TextColor.AQUA) .clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop")))); } 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 70bbd29de..1b583aef5 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 @@ -26,7 +26,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; -import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.block.BlockReplace; @@ -45,6 +45,7 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.world.World; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -67,7 +68,7 @@ public class ClipboardCommands { desc = "Copy the selection to the clipboard" ) @CommandPermissions("worldedit.clipboard.copy") - public void copy(Player player, LocalSession session, EditSession editSession, + public void copy(Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @Switch(name = 'e', desc = "Also copy entities") boolean copyEntities, @@ -76,7 +77,7 @@ public class ClipboardCommands { @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air", def = "") Mask mask) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); - clipboard.setOrigin(session.getPlacementPosition(player)); + clipboard.setOrigin(session.getPlacementPosition(actor)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setCopyingEntities(copyEntities); copy.setCopyingBiomes(copyBiomes); @@ -88,7 +89,7 @@ public class ClipboardCommands { List messages = Lists.newArrayList(); copy.addStatusMessages(messages); - messages.forEach(player::print); + messages.forEach(actor::print); } @Command( @@ -97,7 +98,7 @@ public class ClipboardCommands { ) @CommandPermissions("worldedit.clipboard.cut") @Logging(REGION) - public void cut(Player player, LocalSession session, EditSession editSession, + public void cut(Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @Arg(desc = "Pattern to leave in place of the selection", def = "air") Pattern leavePattern, @@ -109,7 +110,7 @@ public class ClipboardCommands { Mask mask) throws WorldEditException { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); - clipboard.setOrigin(session.getPlacementPosition(player)); + clipboard.setOrigin(session.getPlacementPosition(actor)); ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint()); copy.setSourceFunction(new BlockReplace(editSession, leavePattern)); copy.setCopyingEntities(copyEntities); @@ -123,7 +124,7 @@ public class ClipboardCommands { List messages = Lists.newArrayList(); copy.addStatusMessages(messages); - messages.forEach(player::print); + messages.forEach(actor::print); } @Command( @@ -132,7 +133,7 @@ public class ClipboardCommands { ) @CommandPermissions("worldedit.clipboard.paste") @Logging(PLACEMENT) - public void paste(Player player, LocalSession session, EditSession editSession, + public void paste(Actor actor, World world, LocalSession session, EditSession editSession, @Switch(name = 'a', desc = "Skip air blocks") boolean ignoreAirBlocks, @Switch(name = 'o', desc = "Paste at the original position") @@ -151,7 +152,7 @@ public class ClipboardCommands { Clipboard clipboard = holder.getClipboard(); Region region = clipboard.getRegion(); - BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player); + BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(actor); Operation operation = holder .createPaste(editSession) .to(to) @@ -166,16 +167,16 @@ public class ClipboardCommands { BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin()); Vector3 realTo = to.toVector3().add(holder.getTransform().apply(clipboardOffset.toVector3())); Vector3 max = realTo.add(holder.getTransform().apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3())); - RegionSelector selector = new CuboidRegionSelector(player.getWorld(), realTo.toBlockPoint(), max.toBlockPoint()); - session.setRegionSelector(player.getWorld(), selector); + RegionSelector selector = new CuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint()); + session.setRegionSelector(world, selector); selector.learnChanges(); - selector.explainRegionAdjust(player, session); + selector.explainRegionAdjust(actor, session); } - player.print("The clipboard has been pasted at " + to); + actor.print("The clipboard has been pasted at " + to); List messages = Lists.newArrayList(); operation.addStatusMessages(messages); - messages.forEach(player::print); + messages.forEach(actor::print); } @Command( @@ -186,7 +187,7 @@ public class ClipboardCommands { "Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n" ) @CommandPermissions("worldedit.clipboard.rotate") - public void rotate(Player player, LocalSession session, + public void rotate(Actor actor, LocalSession session, @Arg(desc = "Amount to rotate on the y-axis") double yRotate, @Arg(desc = "Amount to rotate on the x-axis", def = "0") @@ -196,7 +197,7 @@ public class ClipboardCommands { if (Math.abs(yRotate % 90) > 0.001 || Math.abs(xRotate % 90) > 0.001 || Math.abs(zRotate % 90) > 0.001) { - player.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended."); + actor.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended."); } ClipboardHolder holder = session.getClipboard(); @@ -205,7 +206,7 @@ public class ClipboardCommands { transform = transform.rotateX(-xRotate); transform = transform.rotateZ(-zRotate); holder.setTransform(holder.getTransform().combine(transform)); - player.print("The clipboard copy has been rotated."); + actor.print("The clipboard copy has been rotated."); } @Command( @@ -213,14 +214,14 @@ public class ClipboardCommands { desc = "Flip the contents of the clipboard across the origin" ) @CommandPermissions("worldedit.clipboard.flip") - public void flip(Player player, LocalSession session, + public void flip(Actor actor, LocalSession session, @Arg(desc = "The direction to flip, defaults to look direction.", def = Direction.AIM) @Direction BlockVector3 direction) throws WorldEditException { ClipboardHolder holder = session.getClipboard(); AffineTransform transform = new AffineTransform(); transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3()); holder.setTransform(holder.getTransform().combine(transform)); - player.print("The clipboard copy has been flipped."); + actor.print("The clipboard copy has been flipped."); } @Command( @@ -228,8 +229,8 @@ public class ClipboardCommands { desc = "Clear your clipboard" ) @CommandPermissions("worldedit.clipboard.clear") - public void clearClipboard(Player player, LocalSession session) throws WorldEditException { + public void clearClipboard(Actor actor, LocalSession session) throws WorldEditException { session.setClipboard(null); - player.print("Clipboard cleared."); + actor.print("Clipboard cleared."); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java index e931f5225..748c7e3c5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ExpandCommands.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.MultiDirection; import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; @@ -34,6 +35,7 @@ import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import com.sk89q.worldedit.world.World; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandManagerService; @@ -120,7 +122,7 @@ public class ExpandCommands { desc = "Expand the selection area" ) @Logging(REGION) - public void expand(Player player, LocalSession session, + public void expand(Actor actor, World world, LocalSession session, @Arg(desc = "Amount to expand the selection by, can be `vert` to expand to the whole vertical column") int amount, @Arg(desc = "Amount to expand the selection by in the other direction", def = "0") @@ -128,7 +130,7 @@ public class ExpandCommands { @Arg(desc = "Direction to expand", def = Direction.AIM) @MultiDirection List direction) throws WorldEditException { - Region region = session.getSelection(player.getWorld()); + Region region = session.getSelection(world); int oldSize = region.getArea(); if (reverseAmount == 0) { @@ -141,12 +143,12 @@ public class ExpandCommands { } } - session.getRegionSelector(player.getWorld()).learnChanges(); + session.getRegionSelector(world).learnChanges(); int newSize = region.getArea(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + session.getRegionSelector(world).explainRegionAdjust(actor, session); - player.print("Region expanded " + (newSize - oldSize) + " block(s)."); + actor.print("Region expanded " + (newSize - oldSize) + " block(s)."); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 38d92a34e..5fdf2087b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -33,6 +33,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.item.ItemType; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; @@ -72,23 +73,23 @@ public class GeneralCommands { desc = "Modify block change limit" ) @CommandPermissions("worldedit.limit") - public void limit(Player player, LocalSession session, + public void limit(Actor actor, LocalSession session, @Arg(desc = "The limit to set", def = "") Integer limit) { LocalConfiguration config = worldEdit.getConfiguration(); - boolean mayDisable = player.hasPermission("worldedit.limit.unrestricted"); + boolean mayDisable = actor.hasPermission("worldedit.limit.unrestricted"); limit = limit == null ? config.defaultChangeLimit : Math.max(-1, limit); if (!mayDisable && config.maxChangeLimit > -1) { if (limit > config.maxChangeLimit) { - player.printError("Your maximum allowable limit is " + config.maxChangeLimit + "."); + actor.printError("Your maximum allowable limit is " + config.maxChangeLimit + "."); return; } } session.setBlockChangeLimit(limit); - player.print("Block change limit set to " + limit + "." + actor.print("Block change limit set to " + limit + "." + (limit == config.defaultChangeLimit ? "" : " (Use //limit to go back to the default.)")); } @@ -97,22 +98,22 @@ public class GeneralCommands { desc = "Modify evaluation timeout time." ) @CommandPermissions("worldedit.timeout") - public void timeout(Player player, LocalSession session, + public void timeout(Actor actor, LocalSession session, @Arg(desc = "The timeout time to set", def = "") Integer limit) { LocalConfiguration config = worldEdit.getConfiguration(); - boolean mayDisable = player.hasPermission("worldedit.timeout.unrestricted"); + boolean mayDisable = actor.hasPermission("worldedit.timeout.unrestricted"); limit = limit == null ? config.calculationTimeout : Math.max(-1, limit); if (!mayDisable && config.maxCalculationTimeout > -1) { if (limit > config.maxCalculationTimeout) { - player.printError("Your maximum allowable timeout is " + config.maxCalculationTimeout + " ms."); + actor.printError("Your maximum allowable timeout is " + config.maxCalculationTimeout + " ms."); return; } } session.setTimeout(limit); - player.print("Timeout time set to " + limit + " ms." + actor.print("Timeout time set to " + limit + " ms." + (limit == config.calculationTimeout ? "" : " (Use //timeout to go back to the default.)")); } @@ -121,21 +122,21 @@ public class GeneralCommands { desc = "Toggle fast mode" ) @CommandPermissions("worldedit.fast") - public void fast(Player player, LocalSession session, + public void fast(Actor actor, LocalSession session, @Arg(desc = "The new fast mode state", def = "") Boolean fastMode) { boolean hasFastMode = session.hasFastMode(); if (fastMode != null && fastMode == hasFastMode) { - player.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + "."); + actor.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + "."); return; } if (hasFastMode) { session.setFastMode(false); - player.print("Fast mode disabled."); + actor.print("Fast mode disabled."); } else { session.setFastMode(true); - player.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes."); + actor.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes."); } } @@ -144,14 +145,14 @@ public class GeneralCommands { desc = "Sets the reorder mode of WorldEdit" ) @CommandPermissions("worldedit.reorder") - public void reorderMode(Player player, LocalSession session, + public void reorderMode(Actor actor, LocalSession session, @Arg(desc = "The reorder mode", def = "") EditSession.ReorderMode reorderMode) { if (reorderMode == null) { - player.print("The reorder mode is " + session.getReorderMode().getDisplayName()); + actor.print("The reorder mode is " + session.getReorderMode().getDisplayName()); } else { session.setReorderMode(reorderMode); - player.print("The reorder mode is now " + session.getReorderMode().getDisplayName()); + actor.print("The reorder mode is now " + session.getReorderMode().getDisplayName()); } } @@ -182,21 +183,36 @@ public class GeneralCommands { } } + @Command( + name = "/world", + desc = "Sets the world override" + ) + @CommandPermissions("worldedit.world") + public void world(Actor actor, LocalSession session, + @Arg(desc = "The world override", def = "") World world) { + session.setWorldOverride(world); + if (world == null) { + actor.print("Removed world override."); + } else { + actor.print("Set the world override to " + world.getId() + ". (Use //world to go back to default)"); + } + } + @Command( name = "gmask", aliases = {"/gmask"}, desc = "Set the global mask" ) @CommandPermissions("worldedit.global-mask") - public void gmask(Player player, LocalSession session, + public void gmask(Actor actor, LocalSession session, @Arg(desc = "The mask to set", def = "") Mask mask) { if (mask == null) { session.setMask(null); - player.print("Global mask disabled."); + actor.print("Global mask disabled."); } else { session.setMask(mask); - player.print("Global mask set."); + actor.print("Global mask set."); } } 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 96cf412cf..501028d17 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 @@ -27,6 +27,7 @@ import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.annotation.Radii; import com.sk89q.worldedit.internal.annotation.Selection; @@ -73,7 +74,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) - public int hcyl(Player player, LocalSession session, EditSession editSession, + public int hcyl(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") Pattern pattern, @Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W") @@ -81,7 +82,7 @@ public class GenerationCommands { List radii, @Arg(desc = "The height of the cylinder", def = "1") int height) throws WorldEditException { - return cyl(player, session, editSession, pattern, radii, height, true); + return cyl(actor, session, editSession, pattern, radii, height, true); } @Command( @@ -90,7 +91,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.cylinder") @Logging(PLACEMENT) - public int cyl(Player player, LocalSession session, EditSession editSession, + public int cyl(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") Pattern pattern, @Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W") @@ -112,7 +113,7 @@ public class GenerationCommands { break; default: - player.printError("You must either specify 1 or 2 radius values."); + actor.printError("You must either specify 1 or 2 radius values."); return 0; } @@ -120,9 +121,9 @@ public class GenerationCommands { worldEdit.checkMaxRadius(radiusZ); worldEdit.checkMaxRadius(height); - BlockVector3 pos = session.getPlacementPosition(player); + BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.makeCylinder(pos, pattern, radiusX, radiusZ, height, !hollow); - player.print(affected + " block(s) have been created."); + actor.print(affected + " block(s) have been created."); return affected; } @@ -132,7 +133,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.sphere") @Logging(PLACEMENT) - public int hsphere(Player player, LocalSession session, EditSession editSession, + public int hsphere(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") Pattern pattern, @Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W") @@ -140,7 +141,7 @@ public class GenerationCommands { List radii, @Switch(name = 'r', desc = "Raise the bottom of the sphere to the placement position") boolean raised) throws WorldEditException { - return sphere(player, session, editSession, pattern, radii, raised, true); + return sphere(actor, session, editSession, pattern, radii, raised, true); } @Command( @@ -149,7 +150,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.sphere") @Logging(PLACEMENT) - public int sphere(Player player, LocalSession session, EditSession editSession, + public int sphere(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to generate") Pattern pattern, @Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W") @@ -172,7 +173,7 @@ public class GenerationCommands { break; default: - player.printError("You must either specify 1 or 3 radius values."); + actor.printError("You must either specify 1 or 3 radius values."); return 0; } @@ -180,14 +181,16 @@ public class GenerationCommands { worldEdit.checkMaxRadius(radiusY); worldEdit.checkMaxRadius(radiusZ); - BlockVector3 pos = session.getPlacementPosition(player); + BlockVector3 pos = session.getPlacementPosition(actor); if (raised) { pos = pos.add(0, (int) radiusY, 0); } int affected = editSession.makeSphere(pos, pattern, radiusX, radiusY, radiusZ, !hollow); - player.findFreePosition(); - player.print(affected + " block(s) have been created."); + if (actor instanceof Player) { + ((Player) actor).findFreePosition(); + } + actor.print(affected + " block(s) have been created."); return affected; } @@ -197,7 +200,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.forest") @Logging(POSITION) - public int forestGen(Player player, LocalSession session, EditSession editSession, + public int forestGen(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The size of the forest, in blocks", def = "10") int size, @Arg(desc = "The type of forest", def = "tree") @@ -207,8 +210,8 @@ public class GenerationCommands { checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); worldEdit.checkMaxRadius(size); density /= 100; - int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type); - player.print(affected + " trees created."); + int affected = editSession.makeForest(session.getPlacementPosition(actor), size, density, type); + actor.print(affected + " trees created."); return affected; } @@ -218,12 +221,12 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pumpkins") @Logging(POSITION) - public int pumpkins(Player player, LocalSession session, EditSession editSession, + public int pumpkins(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The size of the patch", def = "10") int size) throws WorldEditException { worldEdit.checkMaxRadius(size); - int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), size); - player.print(affected + " pumpkin patches created."); + int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), size); + actor.print(affected + " pumpkin patches created."); return affected; } @@ -233,12 +236,12 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) - public int hollowPyramid(Player player, LocalSession session, EditSession editSession, + public int hollowPyramid(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to set") Pattern pattern, @Arg(desc = "The size of the pyramid") int size) throws WorldEditException { - return pyramid(player, session, editSession, pattern, size, true); + return pyramid(actor, session, editSession, pattern, size, true); } @Command( @@ -247,7 +250,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.pyramid") @Logging(PLACEMENT) - public int pyramid(Player player, LocalSession session, EditSession editSession, + public int pyramid(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The pattern of blocks to set") Pattern pattern, @Arg(desc = "The size of the pyramid") @@ -255,10 +258,12 @@ public class GenerationCommands { @Switch(name = 'h', desc = "Make a hollow pyramid") boolean hollow) throws WorldEditException { worldEdit.checkMaxRadius(size); - BlockVector3 pos = session.getPlacementPosition(player); + BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.makePyramid(pos, pattern, size, !hollow); - player.findFreePosition(); - player.print(affected + " block(s) have been created."); + if (actor instanceof Player) { + ((Player) actor).findFreePosition(); + } + actor.print(affected + " block(s) have been created."); return affected; } @@ -270,7 +275,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.shape") @Logging(ALL) - public int generate(Player player, LocalSession session, EditSession editSession, + public int generate(Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") Pattern pattern, @@ -292,7 +297,7 @@ public class GenerationCommands { zero = Vector3.ZERO; unit = Vector3.ONE; } else if (offset) { - zero = session.getPlacementPosition(player).toVector3(); + zero = session.getPlacementPosition(actor).toVector3(); unit = Vector3.ONE; } else if (offsetCenter) { final Vector3 min = region.getMinimumPoint().toVector3(); @@ -314,11 +319,13 @@ public class GenerationCommands { try { final int affected = editSession.makeShape(region, zero, unit, pattern, String.join(" ", expression), hollow, session.getTimeout()); - player.findFreePosition(); - player.print(affected + " block(s) have been created."); + if (actor instanceof Player) { + ((Player) actor).findFreePosition(); + } + actor.print(affected + " block(s) have been created."); return affected; } catch (ExpressionException e) { - player.printError(e.getMessage()); + actor.printError(e.getMessage()); return 0; } } @@ -331,7 +338,7 @@ public class GenerationCommands { ) @CommandPermissions("worldedit.generation.shape.biome") @Logging(ALL) - public int generateBiome(Player player, LocalSession session, EditSession editSession, + public int generateBiome(Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @Arg(desc = "The biome type to set") BiomeType target, @@ -352,7 +359,7 @@ public class GenerationCommands { zero = Vector3.ZERO; unit = Vector3.ONE; } else if (offset) { - zero = session.getPlacementPosition(player).toVector3(); + zero = session.getPlacementPosition(actor).toVector3(); unit = Vector3.ONE; } else if (offsetCenter) { final Vector3 min = region.getMinimumPoint().toVector3(); @@ -374,11 +381,10 @@ public class GenerationCommands { try { final int affected = editSession.makeBiomeShape(region, zero, unit, target, String.join(" ", expression), hollow, session.getTimeout()); - player.findFreePosition(); - player.print("" + affected + " columns affected."); + actor.print("" + affected + " columns affected."); return affected; } catch (ExpressionException e) { - player.printError(e.getMessage()); + actor.printError(e.getMessage()); return 0; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index afc8b1f0c..d5adc0c59 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -132,9 +133,9 @@ public class HistoryCommands { desc = "Clear your history" ) @CommandPermissions("worldedit.history.clear") - public void clearHistory(Player player, LocalSession session) { + public void clearHistory(Actor actor, LocalSession session) { session.clearHistory(); - player.print("History cleared."); + actor.print("History cleared."); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index e4241dc49..65c1c2f50 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -28,6 +28,7 @@ import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.block.BlockReplace; @@ -54,6 +55,7 @@ import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.util.TreeGenerator.TreeType; +import com.sk89q.worldedit.world.World; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -89,7 +91,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.set") @Logging(REGION) - public int set(Player player, EditSession editSession, + public int set(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") Pattern pattern) { @@ -100,9 +102,9 @@ public class RegionCommands { List messages = Lists.newArrayList(); visitor.addStatusMessages(messages); if (messages.isEmpty()) { - player.print("Operation completed."); + actor.print("Operation completed."); } else { - player.print("Operation completed (" + Joiner.on(", ").join(messages) + ")."); + actor.print("Operation completed (" + Joiner.on(", ").join(messages) + ")."); } return visitor.getAffected(); @@ -115,7 +117,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.line") @Logging(REGION) - public int line(Player player, EditSession editSession, + public int line(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to place") Pattern pattern, @@ -124,7 +126,7 @@ public class RegionCommands { @Switch(name = 'h', desc = "Generate only a shell") boolean shell) throws WorldEditException { if (!(region instanceof CuboidRegion)) { - player.printError("//line only works with cuboid selections"); + actor.printError("//line only works with cuboid selections"); return 0; } checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); @@ -134,7 +136,7 @@ public class RegionCommands { BlockVector3 pos2 = cuboidregion.getPos2(); int blocksChanged = editSession.drawLine(pattern, pos1, pos2, thickness, !shell); - player.print(blocksChanged + " block(s) have been changed."); + actor.print(blocksChanged + " block(s) have been changed."); return blocksChanged; } @@ -145,7 +147,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.curve") @Logging(REGION) - public int curve(Player player, EditSession editSession, + public int curve(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to place") Pattern pattern, @@ -154,7 +156,7 @@ public class RegionCommands { @Switch(name = 'h', desc = "Generate only a shell") boolean shell) throws WorldEditException { if (!(region instanceof ConvexPolyhedralRegion)) { - player.printError("//curve only works with convex polyhedral selections"); + actor.printError("//curve only works with convex polyhedral selections"); return 0; } checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); @@ -164,7 +166,7 @@ public class RegionCommands { int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell); - player.print(blocksChanged + " block(s) have been changed."); + actor.print(blocksChanged + " block(s) have been changed."); return blocksChanged; } @@ -175,7 +177,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.replace") @Logging(REGION) - public int replace(Player player, EditSession editSession, @Selection Region region, + public int replace(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The mask representing blocks to replace", def = "") Mask from, @Arg(desc = "The pattern of blocks to replace with") @@ -184,7 +186,7 @@ public class RegionCommands { from = new ExistingBlockMask(editSession); } int affected = editSession.replaceBlocks(region, from, to); - player.print(affected + " block(s) have been replaced."); + actor.print(affected + " block(s) have been replaced."); return affected; } @@ -194,11 +196,11 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.overlay") @Logging(REGION) - public int overlay(Player player, EditSession editSession, @Selection Region region, + public int overlay(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to overlay") Pattern pattern) throws WorldEditException { int affected = editSession.overlayCuboidBlocks(region, pattern); - player.print(affected + " block(s) have been overlaid."); + actor.print(affected + " block(s) have been overlaid."); return affected; } @@ -209,11 +211,11 @@ public class RegionCommands { ) @Logging(REGION) @CommandPermissions("worldedit.region.center") - public int center(Player player, EditSession editSession, @Selection Region region, + public int center(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") Pattern pattern) throws WorldEditException { int affected = editSession.center(region, pattern); - player.print("Center set (" + affected + " block(s) changed)"); + actor.print("Center set (" + affected + " block(s) changed)"); return affected; } @@ -223,9 +225,9 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.naturalize") @Logging(REGION) - public int naturalize(Player player, EditSession editSession, @Selection Region region) throws WorldEditException { + public int naturalize(Actor actor, EditSession editSession, @Selection Region region) throws WorldEditException { int affected = editSession.naturalizeCuboidBlocks(region); - player.print(affected + " block(s) have been made to look more natural."); + actor.print(affected + " block(s) have been made to look more natural."); return affected; } @@ -235,11 +237,11 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.walls") @Logging(REGION) - public int walls(Player player, EditSession editSession, @Selection Region region, + public int walls(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") Pattern pattern) throws WorldEditException { int affected = editSession.makeWalls(region, pattern); - player.print(affected + " block(s) have been changed."); + actor.print(affected + " block(s) have been changed."); return affected; } @@ -250,11 +252,11 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.faces") @Logging(REGION) - public int faces(Player player, EditSession editSession, @Selection Region region, + public int faces(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") Pattern pattern) throws WorldEditException { int affected = editSession.makeCuboidFaces(region, pattern); - player.print(affected + " block(s) have been changed."); + actor.print(affected + " block(s) have been changed."); return affected; } @@ -265,7 +267,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.smooth") @Logging(REGION) - public int smooth(Player player, EditSession editSession, @Selection Region region, + public int smooth(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "# of iterations to perform", def = "1") int iterations, @Arg(desc = "The mask of blocks to use as the height map", def = "") @@ -273,7 +275,7 @@ public class RegionCommands { HeightMap heightMap = new HeightMap(editSession, region, mask); HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); int affected = heightMap.applyFilter(filter, iterations); - player.print("Terrain's height map smoothed. " + affected + " block(s) changed."); + actor.print("Terrain's height map smoothed. " + affected + " block(s) changed."); return affected; } @@ -283,7 +285,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.move") @Logging(ORIENTATION_REGION) - public int move(Player player, EditSession editSession, LocalSession session, + public int move(Actor actor, World world, EditSession editSession, LocalSession session, @Selection Region region, @Arg(desc = "# of blocks to move", def = "1") int count, @@ -321,14 +323,14 @@ public class RegionCommands { try { region.shift(direction.multiply(count)); - session.getRegionSelector(player.getWorld()).learnChanges(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + session.getRegionSelector(world).learnChanges(); + session.getRegionSelector(world).explainRegionAdjust(actor, session); } catch (RegionOperationException e) { - player.printError(e.getMessage()); + actor.printError(e.getMessage()); } } - player.print(affected + " block(s) moved."); + actor.print(affected + " block(s) moved."); return affected; } @@ -338,7 +340,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.stack") @Logging(ORIENTATION_REGION) - public int stack(Player player, EditSession editSession, LocalSession session, + public int stack(Actor actor, World world, EditSession editSession, LocalSession session, @Selection Region region, @Arg(desc = "# of copies to stack", def = "1") int count, @@ -376,14 +378,14 @@ public class RegionCommands { final BlockVector3 shiftVector = direction.toVector3().multiply(count * (Math.abs(direction.dot(size)) + 1)).toBlockPoint(); region.shift(shiftVector); - session.getRegionSelector(player.getWorld()).learnChanges(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + session.getRegionSelector(world).learnChanges(); + session.getRegionSelector(world).explainRegionAdjust(actor, session); } catch (RegionOperationException e) { - player.printError(e.getMessage()); + actor.printError(e.getMessage()); } } - player.print(affected + " block(s) changed. Undo with //undo"); + actor.print(affected + " block(s) changed. Undo with //undo"); return affected; } @@ -395,15 +397,16 @@ public class RegionCommands { ) @CommandPermissions("worldedit.regen") @Logging(REGION) - public void regenerateChunk(Player player, LocalSession session, EditSession editSession, @Selection Region region) throws WorldEditException { + public void regenerateChunk(Actor actor, World world, LocalSession session, + EditSession editSession, @Selection Region region) throws WorldEditException { Mask mask = session.getMask(); try { session.setMask(null); - player.getWorld().regenerate(region, editSession); + world.regenerate(region, editSession); } finally { session.setMask(mask); } - player.print("Region regenerated."); + actor.print("Region regenerated."); } @Command( @@ -415,7 +418,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.deform") @Logging(ALL) - public int deform(Player player, LocalSession session, EditSession editSession, + public int deform(Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @Arg(desc = "The expression to use", variable = true) List expression, @@ -430,7 +433,7 @@ public class RegionCommands { zero = Vector3.ZERO; unit = Vector3.ONE; } else if (offset) { - zero = session.getPlacementPosition(player).toVector3(); + zero = session.getPlacementPosition(actor).toVector3(); unit = Vector3.ONE; } else { final Vector3 min = region.getMinimumPoint().toVector3(); @@ -446,11 +449,13 @@ public class RegionCommands { try { final int affected = editSession.deformRegion(region, zero, unit, String.join(" ", expression), session.getTimeout()); - player.findFreePosition(); - player.print(affected + " block(s) have been deformed."); + if (actor instanceof Player) { + ((Player) actor).findFreePosition(); + } + actor.print(affected + " block(s) have been deformed."); return affected; } catch (ExpressionException e) { - player.printError(e.getMessage()); + actor.printError(e.getMessage()); return 0; } } @@ -462,7 +467,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.hollow") @Logging(REGION) - public int hollow(Player player, EditSession editSession, + public int hollow(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "Thickness of the shell to leave", def = "0") int thickness, @@ -471,7 +476,7 @@ public class RegionCommands { checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); int affected = editSession.hollowOutRegion(region, thickness, pattern); - player.print(affected + " block(s) have been changed."); + actor.print(affected + " block(s) have been changed."); return affected; } @@ -481,14 +486,14 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.forest") @Logging(REGION) - public int forest(Player player, EditSession editSession, @Selection Region region, + public int forest(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The type of tree to place", def = "tree") TreeType type, @Arg(desc = "The density of the forest", def = "5") double density) throws WorldEditException { checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); int affected = editSession.makeForest(region, density / 100, type); - player.print(affected + " trees created."); + actor.print(affected + " trees created."); return affected; } @@ -498,7 +503,7 @@ public class RegionCommands { ) @CommandPermissions("worldedit.region.flora") @Logging(REGION) - public int flora(Player player, EditSession editSession, @Selection Region region, + public int flora(Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The density of the forest", def = "5") double density) throws WorldEditException { checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); @@ -510,7 +515,7 @@ public class RegionCommands { Operations.completeLegacy(visitor); int affected = ground.getAffected(); - player.print(affected + " flora created."); + actor.print(affected + " flora created."); return affected; } 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 07425d35a..321537a71 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 @@ -99,7 +99,7 @@ public class SchematicCommands { desc = "Load a schematic into your clipboard" ) @CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load"}) - public void load(Player player, LocalSession session, + public void load(Actor actor, LocalSession session, @Arg(desc = "File name.") String filename, @Arg(desc = "Format name.", def = "sponge") @@ -107,12 +107,12 @@ public class SchematicCommands { LocalConfiguration config = worldEdit.getConfiguration(); File dir = worldEdit.getWorkingDirectoryFile(config.saveDir); - File f = worldEdit.getSafeOpenFile(player, dir, filename, + File f = worldEdit.getSafeOpenFile(actor, dir, filename, BuiltInClipboardFormat.SPONGE_SCHEMATIC.getPrimaryFileExtension(), ClipboardFormats.getFileExtensionArray()); if (!f.exists()) { - player.printError("Schematic " + filename + " does not exist!"); + actor.printError("Schematic " + filename + " does not exist!"); return; } @@ -121,12 +121,12 @@ public class SchematicCommands { format = ClipboardFormats.findByAlias(formatName); } if (format == null) { - player.printError("Unknown schematic format: " + formatName); + actor.printError("Unknown schematic format: " + formatName); return; } - SchematicLoadTask task = new SchematicLoadTask(player, f, format); - AsyncCommandBuilder.wrap(task, player) + SchematicLoadTask task = new SchematicLoadTask(actor, f, format); + AsyncCommandBuilder.wrap(task, actor) .registerWithSupervisor(worldEdit.getSupervisor(), "Loading schematic " + filename) .sendMessageAfterDelay("(Please wait... loading schematic.)") .onSuccess(TextComponent.of(filename, TextColor.GOLD) @@ -142,7 +142,7 @@ public class SchematicCommands { desc = "Save a schematic into your clipboard" ) @CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save"}) - public void save(Player player, LocalSession session, + public void save(Actor actor, LocalSession session, @Arg(desc = "File name.") String filename, @Arg(desc = "Format name.", def = "sponge") @@ -156,19 +156,19 @@ public class SchematicCommands { ClipboardFormat format = ClipboardFormats.findByAlias(formatName); if (format == null) { - player.printError("Unknown schematic format: " + formatName); + actor.printError("Unknown schematic format: " + formatName); return; } - File f = worldEdit.getSafeSaveFile(player, dir, filename, format.getPrimaryFileExtension()); + File f = worldEdit.getSafeSaveFile(actor, dir, filename, format.getPrimaryFileExtension()); boolean overwrite = f.exists(); if (overwrite) { - if (!player.hasPermission("worldedit.schematic.delete")) { + if (!actor.hasPermission("worldedit.schematic.delete")) { throw new StopExecutionException(TextComponent.of("That schematic already exists!")); } if (!allowOverwrite) { - player.printError("That schematic already exists. Use the -f flag to overwrite it."); + actor.printError("That schematic already exists. Use the -f flag to overwrite it."); return; } } @@ -184,8 +184,8 @@ public class SchematicCommands { ClipboardHolder holder = session.getClipboard(); - SchematicSaveTask task = new SchematicSaveTask(player, f, format, holder, overwrite); - AsyncCommandBuilder.wrap(task, player) + SchematicSaveTask task = new SchematicSaveTask(actor, f, format, holder, overwrite); + AsyncCommandBuilder.wrap(task, actor) .registerWithSupervisor(worldEdit.getSupervisor(), "Saving schematic " + filename) .sendMessageAfterDelay("(Please wait... saving schematic.)") .onSuccess(filename + " saved" + (overwrite ? " (overwriting previous file)." : "."), null) @@ -278,12 +278,12 @@ public class SchematicCommands { } private static class SchematicLoadTask implements Callable { - private final Player player; + private final Actor actor; private final File file; private final ClipboardFormat format; - SchematicLoadTask(Player player, File file, ClipboardFormat format) { - this.player = player; + SchematicLoadTask(Actor actor, File file, ClipboardFormat format) { + this.actor = actor; this.file = file; this.format = format; } @@ -296,21 +296,21 @@ public class SchematicCommands { ClipboardReader reader = closer.register(format.getReader(bis)); Clipboard clipboard = reader.read(); - log.info(player.getName() + " loaded " + file.getCanonicalPath()); + log.info(actor.getName() + " loaded " + file.getCanonicalPath()); return new ClipboardHolder(clipboard); } } } private static class SchematicSaveTask implements Callable { - private final Player player; + private final Actor actor; private final File file; private final ClipboardFormat format; private final ClipboardHolder holder; private final boolean overwrite; - SchematicSaveTask(Player player, File file, ClipboardFormat format, ClipboardHolder holder, boolean overwrite) { - this.player = player; + SchematicSaveTask(Actor actor, File file, ClipboardFormat format, ClipboardHolder holder, boolean overwrite) { + this.actor = actor; this.file = file; this.format = format; this.holder = holder; @@ -339,7 +339,7 @@ public class SchematicCommands { ClipboardWriter writer = closer.register(format.getWriter(bos)); writer.write(target); - log.info(player.getName() + " saved " + file.getCanonicalPath() + (overwrite ? " (overwriting previous file)" : "")); + log.info(actor.getName() + " saved " + file.getCanonicalPath() + (overwrite ? " (overwriting previous file)" : "")); } return null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 88285e475..431785923 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -33,6 +33,8 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.block.BlockDistributionCounter; @@ -104,23 +106,26 @@ public class SelectionCommands { ) @Logging(POSITION) @CommandPermissions("worldedit.selection.pos") - public void pos1(Player player, LocalSession session, + public void pos1(Actor actor, World world, LocalSession session, @Arg(desc = "Coordinates to set position 1 to", def = "") BlockVector3 coordinates) throws WorldEditException { Location pos; if (coordinates != null) { - pos = new Location(player.getWorld(), coordinates.toVector3()); + pos = new Location(world, coordinates.toVector3()); + } else if (actor instanceof Locatable) { + pos = ((Locatable) actor).getBlockLocation(); } else { - pos = player.getBlockIn(); - } - - if (!session.getRegionSelector(player.getWorld()).selectPrimary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(player))) { - player.printError("Position already set."); + actor.printError("You must provide coordinates as console."); return; } - session.getRegionSelector(player.getWorld()) - .explainPrimarySelection(player, session, pos.toVector().toBlockPoint()); + if (!session.getRegionSelector(world).selectPrimary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) { + actor.printError("Position already set."); + return; + } + + session.getRegionSelector(world) + .explainPrimarySelection(actor, session, pos.toVector().toBlockPoint()); } @Command( @@ -129,23 +134,26 @@ public class SelectionCommands { ) @Logging(POSITION) @CommandPermissions("worldedit.selection.pos") - public void pos2(Player player, LocalSession session, + public void pos2(Actor actor, World world, LocalSession session, @Arg(desc = "Coordinates to set position 2 to", def = "") BlockVector3 coordinates) throws WorldEditException { Location pos; if (coordinates != null) { - pos = new Location(player.getWorld(), coordinates.toVector3()); + pos = new Location(world, coordinates.toVector3()); + } else if (actor instanceof Locatable) { + pos = ((Locatable) actor).getBlockLocation(); } else { - pos = player.getBlockIn(); - } - - if (!session.getRegionSelector(player.getWorld()).selectSecondary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(player))) { - player.printError("Position already set."); + actor.printError("You must provide coordinates as console."); return; } - session.getRegionSelector(player.getWorld()) - .explainSecondarySelection(player, session, pos.toVector().toBlockPoint()); + if (!session.getRegionSelector(world).selectSecondary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) { + actor.printError("Position already set."); + return; + } + + session.getRegionSelector(world) + .explainSecondarySelection(actor, session, pos.toVector().toBlockPoint()); } @Command( @@ -229,7 +237,7 @@ public class SelectionCommands { : ChunkStore.toChunk(coordinates.toBlockVector3()); } else { // use player loc - min2D = ChunkStore.toChunk(player.getBlockIn().toVector().toBlockPoint()); + min2D = ChunkStore.toChunk(player.getBlockLocation().toVector().toBlockPoint()); } min = BlockVector3.at(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); @@ -302,7 +310,7 @@ public class SelectionCommands { ) @Logging(REGION) @CommandPermissions("worldedit.selection.contract") - public void contract(Player player, LocalSession session, + public void contract(Actor actor, World world, LocalSession session, @Arg(desc = "Amount to contract the selection by") int amount, @Arg(desc = "Amount to contract the selection by in the other direction", def = "0") @@ -311,7 +319,7 @@ public class SelectionCommands { @MultiDirection List direction) throws WorldEditException { try { - Region region = session.getSelection(player.getWorld()); + Region region = session.getSelection(world); int oldSize = region.getArea(); if (reverseAmount == 0) { for (BlockVector3 dir : direction) { @@ -322,15 +330,14 @@ public class SelectionCommands { region.contract(dir.multiply(amount), dir.multiply(-reverseAmount)); } } - session.getRegionSelector(player.getWorld()).learnChanges(); + session.getRegionSelector(world).learnChanges(); int newSize = region.getArea(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + session.getRegionSelector(world).explainRegionAdjust(actor, session); - - player.print("Region contracted " + (oldSize - newSize) + " blocks."); + actor.print("Region contracted " + (oldSize - newSize) + " blocks."); } catch (RegionOperationException e) { - player.printError(e.getMessage()); + actor.printError(e.getMessage()); } } @@ -340,26 +347,26 @@ public class SelectionCommands { ) @Logging(REGION) @CommandPermissions("worldedit.selection.shift") - public void shift(Player player, LocalSession session, + public void shift(Actor actor, World world, LocalSession session, @Arg(desc = "Amount to shift the selection by") int amount, @Arg(desc = "Direction to contract", def = Direction.AIM) @MultiDirection List direction) throws WorldEditException { try { - Region region = session.getSelection(player.getWorld()); + Region region = session.getSelection(world); for (BlockVector3 dir : direction) { region.shift(dir.multiply(amount)); } - session.getRegionSelector(player.getWorld()).learnChanges(); + session.getRegionSelector(world).learnChanges(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); + session.getRegionSelector(world).explainRegionAdjust(actor, session); - player.print("Region shifted."); + actor.print("Region shifted."); } catch (RegionOperationException e) { - player.printError(e.getMessage()); + actor.printError(e.getMessage()); } } @@ -369,18 +376,18 @@ public class SelectionCommands { ) @Logging(REGION) @CommandPermissions("worldedit.selection.outset") - public void outset(Player player, LocalSession session, + public void outset(Actor actor, World world, LocalSession session, @Arg(desc = "Amount to expand the selection by in all directions") int amount, @Switch(name = 'h', desc = "Only expand horizontally") boolean onlyHorizontal, @Switch(name = 'v', desc = "Only expand vertically") boolean onlyVertical) throws WorldEditException { - Region region = session.getSelection(player.getWorld()); + Region region = session.getSelection(world); region.expand(getChangesForEachDir(amount, onlyHorizontal, onlyVertical)); - session.getRegionSelector(player.getWorld()).learnChanges(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - player.print("Region outset."); + session.getRegionSelector(world).learnChanges(); + session.getRegionSelector(world).explainRegionAdjust(actor, session); + actor.print("Region outset."); } @Command( @@ -389,18 +396,18 @@ public class SelectionCommands { ) @Logging(REGION) @CommandPermissions("worldedit.selection.inset") - public void inset(Player player, LocalSession session, + public void inset(Actor actor, World world, LocalSession session, @Arg(desc = "Amount to contract the selection by in all directions") int amount, @Switch(name = 'h', desc = "Only contract horizontally") boolean onlyHorizontal, @Switch(name = 'v', desc = "Only contract vertically") boolean onlyVertical) throws WorldEditException { - Region region = session.getSelection(player.getWorld()); + Region region = session.getSelection(world); region.contract(getChangesForEachDir(amount, onlyHorizontal, onlyVertical)); - session.getRegionSelector(player.getWorld()).learnChanges(); - session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session); - player.print("Region inset."); + session.getRegionSelector(world).learnChanges(); + session.getRegionSelector(world).explainRegionAdjust(actor, session); + actor.print("Region inset."); } private BlockVector3[] getChangesForEachDir(int amount, boolean onlyHorizontal, boolean onlyVertical) { @@ -519,16 +526,15 @@ public class SelectionCommands { aliases = { ";", "/desel", "/deselect" }, desc = "Choose a region selector" ) - public void select(Player player, LocalSession session, + public void select(Actor actor, World world, LocalSession session, @Arg(desc = "Selector to switch to", def = "") SelectorChoice selector, @Switch(name = 'd', desc = "Set default selector") boolean setDefaultSelector) throws WorldEditException { - final World world = player.getWorld(); if (selector == null) { session.getRegionSelector(world).clear(); - session.dispatchCUISelection(player); - player.print("Selection cleared."); + session.dispatchCUISelection(actor); + actor.print("Selection cleared."); return; } @@ -538,38 +544,38 @@ public class SelectionCommands { switch (selector) { case CUBOID: newSelector = new CuboidRegionSelector(oldSelector); - player.print("Cuboid: left click for point 1, right click for point 2"); + actor.print("Cuboid: left click for point 1, right click for point 2"); break; case EXTEND: newSelector = new ExtendingCuboidRegionSelector(oldSelector); - player.print("Cuboid: left click for a starting point, right click to extend"); + actor.print("Cuboid: left click for a starting point, right click to extend"); break; case POLY: { newSelector = new Polygonal2DRegionSelector(oldSelector); - player.print("2D polygon selector: Left/right click to add a point."); - Optional limit = ActorSelectorLimits.forActor(player).getPolygonVertexLimit(); - limit.ifPresent(integer -> player.print(integer + " points maximum.")); + actor.print("2D polygon selector: Left/right click to add a point."); + Optional limit = ActorSelectorLimits.forActor(actor).getPolygonVertexLimit(); + limit.ifPresent(integer -> actor.print(integer + " points maximum.")); break; } case ELLIPSOID: newSelector = new EllipsoidRegionSelector(oldSelector); - player.print("Ellipsoid selector: left click=center, right click to extend"); + actor.print("Ellipsoid selector: left click=center, right click to extend"); break; case SPHERE: newSelector = new SphereRegionSelector(oldSelector); - player.print("Sphere selector: left click=center, right click to set radius"); + actor.print("Sphere selector: left click=center, right click to set radius"); break; case CYL: newSelector = new CylinderRegionSelector(oldSelector); - player.print("Cylindrical selector: Left click=center, right click to extend."); + actor.print("Cylindrical selector: Left click=center, right click to extend."); break; case CONVEX: case HULL: case POLYHEDRON: { newSelector = new ConvexPolyhedralRegionSelector(oldSelector); - player.print("Convex polyhedral selector: Left click=First vertex, right click to add more."); - Optional limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit(); - limit.ifPresent(integer -> player.print(integer + " points maximum.")); + actor.print("Convex polyhedral selector: Left click=First vertex, right click to add more."); + Optional limit = ActorSelectorLimits.forActor(actor).getPolyhedronVertexLimit(); + limit.ifPresent(integer -> actor.print(integer + " points maximum.")); break; } case LIST: @@ -587,7 +593,7 @@ public class SelectionCommands { box.appendCommand("cyl", "Select a cylinder", "//sel cyl"); box.appendCommand("convex", "Select a convex polyhedral", "//sel convex"); - player.print(box.create(1)); + actor.print(box.create(1)); return; } @@ -602,14 +608,14 @@ public class SelectionCommands { if (found != null) { session.setDefaultRegionSelector(found); - player.print("Your default region selector is now " + found.name() + "."); + actor.print("Your default region selector is now " + found.name() + "."); } else { throw new RuntimeException("Something unexpected happened. Please report this."); } } session.setRegionSelector(world, newSelector); - session.dispatchCUISelection(player); + session.dispatchCUISelection(actor); } private static class BlockDistributionResult extends PaginationBox { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java index 30728ed53..da839703f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java @@ -28,12 +28,14 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException; import com.sk89q.worldedit.world.snapshot.Snapshot; import com.sk89q.worldedit.world.storage.MissingWorldException; @@ -67,24 +69,24 @@ public class SnapshotCommands { desc = "List snapshots" ) @CommandPermissions("worldedit.snapshots.list") - public void list(Player player, + public void list(Actor actor, World world, @ArgFlag(name = 'p', desc = "Page of results to return", def = "1") int page) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); + actor.printError("Snapshot/backup restore is not configured."); return; } try { - List snapshots = config.snapshotRepo.getSnapshots(true, player.getWorld().getName()); + List snapshots = config.snapshotRepo.getSnapshots(true, world.getName()); if (!snapshots.isEmpty()) { - player.print(new SnapshotListBox(player.getWorld().getName(), snapshots).create(page)); + actor.print(new SnapshotListBox(world.getName(), snapshots).create(page)); } else { - player.printError("No snapshots are available. See console for details."); + actor.printError("No snapshots are available. See console for details."); // Okay, let's toss some debugging information! File dir = config.snapshotRepo.getDirectory(); @@ -99,7 +101,7 @@ public class SnapshotCommands { } } } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); + actor.printError("No snapshots were found for this world."); } } @@ -108,37 +110,37 @@ public class SnapshotCommands { desc = "Choose a snapshot to use" ) @CommandPermissions("worldedit.snapshots.restore") - public void use(Player player, LocalSession session, + public void use(Actor actor, World world, LocalSession session, @Arg(desc = "Snapeshot to use") String name) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); + actor.printError("Snapshot/backup restore is not configured."); return; } // Want the latest snapshot? if (name.equalsIgnoreCase("latest")) { try { - Snapshot snapshot = config.snapshotRepo.getDefaultSnapshot(player.getWorld().getName()); + Snapshot snapshot = config.snapshotRepo.getDefaultSnapshot(world.getName()); if (snapshot != null) { session.setSnapshot(null); - player.print("Now using newest snapshot."); + actor.print("Now using newest snapshot."); } else { - player.printError("No snapshots were found."); + actor.printError("No snapshots were found."); } } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); + actor.printError("No snapshots were found for this world."); } } else { try { session.setSnapshot(config.snapshotRepo.getSnapshot(name)); - player.print("Snapshot set to: " + name); + actor.print("Snapshot set to: " + name); } catch (InvalidSnapshotException e) { - player.printError("That snapshot does not exist or is not available."); + actor.printError("That snapshot does not exist or is not available."); } } } @@ -148,36 +150,36 @@ public class SnapshotCommands { desc = "Choose the snapshot based on the list id" ) @CommandPermissions("worldedit.snapshots.restore") - public void sel(Player player, LocalSession session, + public void sel(Actor actor, World world, LocalSession session, @Arg(desc = "The list ID to select") int index) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); + actor.printError("Snapshot/backup restore is not configured."); return; } if (index < 1) { - player.printError("Invalid index, must be equal or higher then 1."); + actor.printError("Invalid index, must be equal or higher then 1."); return; } try { - List snapshots = config.snapshotRepo.getSnapshots(true, player.getWorld().getName()); + List snapshots = config.snapshotRepo.getSnapshots(true, world.getName()); if (snapshots.size() < index) { - player.printError("Invalid index, must be between 1 and " + snapshots.size() + "."); + actor.printError("Invalid index, must be between 1 and " + snapshots.size() + "."); return; } Snapshot snapshot = snapshots.get(index - 1); if (snapshot == null) { - player.printError("That snapshot does not exist or is not available."); + actor.printError("That snapshot does not exist or is not available."); return; } session.setSnapshot(snapshot); - player.print("Snapshot set to: " + snapshot.getName()); + actor.print("Snapshot set to: " + snapshot.getName()); } catch (MissingWorldException e) { - player.printError("No snapshots were found for this world."); + actor.printError("No snapshots were found for this world."); } } @@ -186,29 +188,29 @@ public class SnapshotCommands { desc = "Choose the nearest snapshot before a date" ) @CommandPermissions("worldedit.snapshots.restore") - public void before(Player player, LocalSession session, + public void before(Actor actor, World world, LocalSession session, @Arg(desc = "The soonest date that may be used") ZonedDateTime date) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); + actor.printError("Snapshot/backup restore is not configured."); return; } try { - Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName()); + Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, world.getName()); if (snapshot == null) { - player.printError("Couldn't find a snapshot before " + actor.printError("Couldn't find a snapshot before " + dateFormat.withZone(session.getTimeZone()).format(date) + "."); } else { session.setSnapshot(snapshot); - player.print("Snapshot set to: " + snapshot.getName()); + actor.print("Snapshot set to: " + snapshot.getName()); } } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); + actor.printError("No snapshots were found for this world."); } } @@ -217,28 +219,28 @@ public class SnapshotCommands { desc = "Choose the nearest snapshot after a date" ) @CommandPermissions("worldedit.snapshots.restore") - public void after(Player player, LocalSession session, + public void after(Actor actor, World world, LocalSession session, @Arg(desc = "The soonest date that may be used") ZonedDateTime date) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); + actor.printError("Snapshot/backup restore is not configured."); return; } try { - Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName()); + Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, world.getName()); if (snapshot == null) { - player.printError("Couldn't find a snapshot after " + actor.printError("Couldn't find a snapshot after " + dateFormat.withZone(session.getTimeZone()).format(date) + "."); } else { session.setSnapshot(snapshot); - player.print("Snapshot set to: " + snapshot.getName()); + actor.print("Snapshot set to: " + snapshot.getName()); } } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); + actor.printError("No snapshots were found for this world."); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java index 0b9ba7cfe..f8dd5689a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotUtilCommands.java @@ -27,9 +27,10 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.Logging; -import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.DataException; +import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException; import com.sk89q.worldedit.world.snapshot.Snapshot; import com.sk89q.worldedit.world.snapshot.SnapshotRestore; @@ -60,25 +61,25 @@ public class SnapshotUtilCommands { ) @Logging(REGION) @CommandPermissions("worldedit.snapshots.restore") - public void restore(Player player, LocalSession session, EditSession editSession, + public void restore(Actor actor, World world, LocalSession session, EditSession editSession, @Arg(name = "snapshot", desc = "The snapshot to restore", def = "") String snapshotName) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); + actor.printError("Snapshot/backup restore is not configured."); return; } - Region region = session.getSelection(player.getWorld()); + Region region = session.getSelection(world); Snapshot snapshot; if (snapshotName != null) { try { snapshot = config.snapshotRepo.getSnapshot(snapshotName); } catch (InvalidSnapshotException e) { - player.printError("That snapshot does not exist or is not available."); + actor.printError("That snapshot does not exist or is not available."); return; } } else { @@ -88,10 +89,10 @@ public class SnapshotUtilCommands { // No snapshot set? if (snapshot == null) { try { - snapshot = config.snapshotRepo.getDefaultSnapshot(player.getWorld().getName()); + snapshot = config.snapshotRepo.getDefaultSnapshot(world.getName()); if (snapshot == null) { - player.printError("No snapshots were found. See console for details."); + actor.printError("No snapshots were found. See console for details."); // Okay, let's toss some debugging information! File dir = config.snapshotRepo.getDirectory(); @@ -108,7 +109,7 @@ public class SnapshotUtilCommands { return; } } catch (MissingWorldException ex) { - player.printError("No snapshots were found for this world."); + actor.printError("No snapshots were found for this world."); return; } } @@ -118,9 +119,9 @@ public class SnapshotUtilCommands { // Load chunk store try { chunkStore = snapshot.getChunkStore(); - player.print("Snapshot '" + snapshot.getName() + "' loaded; now restoring..."); + actor.print("Snapshot '" + snapshot.getName() + "' loaded; now restoring..."); } catch (DataException | IOException e) { - player.printError("Failed to load snapshot: " + e.getMessage()); + actor.printError("Failed to load snapshot: " + e.getMessage()); return; } @@ -134,15 +135,15 @@ public class SnapshotUtilCommands { if (restore.hadTotalFailure()) { String error = restore.getLastErrorMessage(); if (!restore.getMissingChunks().isEmpty()) { - player.printError("Chunks were not present in snapshot."); + actor.printError("Chunks were not present in snapshot."); } else if (error != null) { - player.printError("Errors prevented any blocks from being restored."); - player.printError("Last error: " + error); + actor.printError("Errors prevented any blocks from being restored."); + actor.printError("Last error: " + error); } else { - player.printError("No chunks could be loaded. (Bad archive?)"); + actor.printError("No chunks could be loaded. (Bad archive?)"); } } else { - player.print(String.format("Restored; %d " + actor.print(String.format("Restored; %d " + "missing chunks and %d other errors.", restore.getMissingChunks().size(), restore.getErrorChunks().size())); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java index 9d3765943..c70e452e0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java @@ -36,10 +36,7 @@ import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.PrintCommandHelp; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Entity; -import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extension.platform.Capability; -import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.function.EntityFunction; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask; @@ -49,7 +46,6 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; -import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CylinderRegion; @@ -90,7 +86,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fill") @Logging(PLACEMENT) - public int fill(Player player, LocalSession session, EditSession editSession, + public int fill(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The blocks to fill with") Pattern pattern, @Arg(desc = "The radius to fill in") @@ -101,9 +97,9 @@ public class UtilityCommands { we.checkMaxRadius(radius); depth = Math.max(1, depth); - BlockVector3 pos = session.getPlacementPosition(player); + BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.fillXZ(pos, pattern, radius, depth, false); - player.print(affected + " block(s) have been created."); + actor.print(affected + " block(s) have been created."); return affected; } @@ -113,7 +109,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fill.recursive") @Logging(PLACEMENT) - public int fillr(Player player, LocalSession session, EditSession editSession, + public int fillr(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The blocks to fill with") Pattern pattern, @Arg(desc = "The radius to fill in") @@ -125,9 +121,9 @@ public class UtilityCommands { depth = depth == null ? Integer.MAX_VALUE : Math.max(1, depth); we.checkMaxRadius(radius); - BlockVector3 pos = session.getPlacementPosition(player); + BlockVector3 pos = session.getPlacementPosition(actor); int affected = editSession.fillXZ(pos, pattern, radius, depth, true); - player.print(affected + " block(s) have been created."); + actor.print(affected + " block(s) have been created."); return affected; } @@ -137,7 +133,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.drain") @Logging(PLACEMENT) - public int drain(Player player, LocalSession session, EditSession editSession, + public int drain(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius to drain") double radius, @Switch(name = 'w', desc = "Also un-waterlog blocks") @@ -145,8 +141,8 @@ public class UtilityCommands { radius = Math.max(0, radius); we.checkMaxRadius(radius); int affected = editSession.drainArea( - session.getPlacementPosition(player), radius, waterlogged); - player.print(affected + " block(s) have been changed."); + session.getPlacementPosition(actor), radius, waterlogged); + actor.print(affected + " block(s) have been changed."); return affected; } @@ -157,13 +153,13 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fixlava") @Logging(PLACEMENT) - public int fixLava(Player player, LocalSession session, EditSession editSession, + public int fixLava(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius to fix in") double radius) throws WorldEditException { radius = Math.max(0, radius); we.checkMaxRadius(radius); - int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.LAVA); - player.print(affected + " block(s) have been changed."); + int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.LAVA); + actor.print(affected + " block(s) have been changed."); return affected; } @@ -174,13 +170,13 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.fixwater") @Logging(PLACEMENT) - public int fixWater(Player player, LocalSession session, EditSession editSession, + public int fixWater(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius to fix in") double radius) throws WorldEditException { radius = Math.max(0, radius); we.checkMaxRadius(radius); - int affected = editSession.fixLiquid(session.getPlacementPosition(player), radius, BlockTypes.WATER); - player.print(affected + " block(s) have been changed."); + int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.WATER); + actor.print(affected + " block(s) have been changed."); return affected; } @@ -191,18 +187,17 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removeabove") @Logging(PLACEMENT) - public int removeAbove(Player player, LocalSession session, EditSession editSession, + public int removeAbove(Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "The apothem of the square to remove from", def = "1") int size, @Arg(desc = "The maximum height above you to remove from", def = "") Integer height) throws WorldEditException { size = Math.max(1, size); we.checkMaxRadius(size); - World world = player.getWorld(); height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1); - int affected = editSession.removeAbove(session.getPlacementPosition(player), size, height); - player.print(affected + " block(s) have been removed."); + int affected = editSession.removeAbove(session.getPlacementPosition(actor), size, height); + actor.print(affected + " block(s) have been removed."); return affected; } @@ -213,18 +208,17 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removebelow") @Logging(PLACEMENT) - public int removeBelow(Player player, LocalSession session, EditSession editSession, + public int removeBelow(Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "The apothem of the square to remove from", def = "1") int size, @Arg(desc = "The maximum height below you to remove from", def = "") Integer height) throws WorldEditException { size = Math.max(1, size); we.checkMaxRadius(size); - World world = player.getWorld(); height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1); - int affected = editSession.removeBelow(session.getPlacementPosition(player), size, height); - player.print(affected + " block(s) have been removed."); + int affected = editSession.removeBelow(session.getPlacementPosition(actor), size, height); + actor.print(affected + " block(s) have been removed."); return affected; } @@ -235,7 +229,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.removenear") @Logging(PLACEMENT) - public int removeNear(Player player, LocalSession session, EditSession editSession, + public int removeNear(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The mask of blocks to remove") Mask mask, @Arg(desc = "The radius of the square to remove from", def = "50") @@ -243,8 +237,8 @@ public class UtilityCommands { radius = Math.max(1, radius); we.checkMaxRadius(radius); - int affected = editSession.removeNear(session.getPlacementPosition(player), mask, radius); - player.print(affected + " block(s) have been removed."); + int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, radius); + actor.print(affected + " block(s) have been removed."); return affected; } @@ -255,7 +249,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.replacenear") @Logging(PLACEMENT) - public int replaceNear(Player player, LocalSession session, EditSession editSession, + public int replaceNear(Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the square to remove in") int radius, @Arg(desc = "The mask matching blocks to remove", def = "") @@ -265,17 +259,17 @@ public class UtilityCommands { radius = Math.max(1, radius); we.checkMaxRadius(radius); - BlockVector3 base = session.getPlacementPosition(player); + BlockVector3 base = session.getPlacementPosition(actor); BlockVector3 min = base.subtract(radius, radius, radius); BlockVector3 max = base.add(radius, radius, radius); - Region region = new CuboidRegion(player.getWorld(), min, max); + Region region = new CuboidRegion(world, min, max); if (from == null) { from = new ExistingBlockMask(editSession); } int affected = editSession.replaceBlocks(region, from, to); - player.print(affected + " block(s) have been replaced."); + actor.print(affected + " block(s) have been replaced."); return affected; } @@ -286,14 +280,14 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.snow") @Logging(PLACEMENT) - public int snow(Player player, LocalSession session, EditSession editSession, + public int snow(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the circle to snow in", def = "10") double size) throws WorldEditException { size = Math.max(1, size); we.checkMaxRadius(size); - int affected = editSession.simulateSnow(session.getPlacementPosition(player), size); - player.print(affected + " surface(s) covered. Let it snow~"); + int affected = editSession.simulateSnow(session.getPlacementPosition(actor), size); + actor.print(affected + " surface(s) covered. Let it snow~"); return affected; } @@ -304,14 +298,14 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.thaw") @Logging(PLACEMENT) - public int thaw(Player player, LocalSession session, EditSession editSession, + public int thaw(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the circle to thaw in", def = "10") double size) throws WorldEditException { size = Math.max(1, size); we.checkMaxRadius(size); - int affected = editSession.thaw(session.getPlacementPosition(player), size); - player.print(affected + " surface(s) thawed."); + int affected = editSession.thaw(session.getPlacementPosition(actor), size); + actor.print(affected + " surface(s) thawed."); return affected; } @@ -322,7 +316,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.green") @Logging(PLACEMENT) - public int green(Player player, LocalSession session, EditSession editSession, + public int green(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the circle to convert in", def = "10") double size, @Switch(name = 'f', desc = "Also convert coarse dirt") @@ -331,8 +325,8 @@ public class UtilityCommands { we.checkMaxRadius(size); final boolean onlyNormalDirt = !convertCoarse; - final int affected = editSession.green(session.getPlacementPosition(player), size, onlyNormalDirt); - player.print(affected + " surface(s) greened."); + final int affected = editSession.green(session.getPlacementPosition(actor), size, onlyNormalDirt); + actor.print(affected + " surface(s) greened."); return affected; } @@ -343,7 +337,7 @@ public class UtilityCommands { ) @CommandPermissions("worldedit.extinguish") @Logging(PLACEMENT) - public void extinguish(Player player, LocalSession session, EditSession editSession, + public void extinguish(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The radius of the square to remove in", def = "") Integer radius) throws WorldEditException { @@ -354,8 +348,8 @@ public class UtilityCommands { we.checkMaxRadius(size); Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE); - int affected = editSession.removeNear(session.getPlacementPosition(player), mask, size); - player.print(affected + " block(s) have been removed."); + int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, size); + actor.print(affected + " block(s) have been removed."); } @Command( @@ -384,7 +378,6 @@ public class UtilityCommands { @Switch(name = 'r', desc = "Also destroy armor stands") boolean killArmorStands) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); - Player player = actor instanceof Player ? (Player) actor : null; if (radius == null) { radius = config.butcherDefaultRadius; @@ -410,7 +403,7 @@ public class UtilityCommands { flags.or(CreatureButcher.Flags.TAGGED, killWithName, "worldedit.butcher.tagged"); flags.or(CreatureButcher.Flags.ARMOR_STAND, killArmorStands, "worldedit.butcher.armorstands"); - int killed = killMatchingEntities(radius, player, flags::createFunction); + int killed = killMatchingEntities(radius, actor, flags::createFunction); actor.print("Killed " + killed + (killed != 1 ? " mobs" : " mob") + (radius < 0 ? "" : " in a radius of " + radius) + "."); @@ -429,43 +422,32 @@ public class UtilityCommands { EntityRemover remover, @Arg(desc = "The radius of the cuboid to remove from") int radius) throws WorldEditException { - Player player = actor instanceof Player ? (Player) actor : null; - if (radius < -1) { actor.printError("Use -1 to remove all entities in loaded chunks"); return 0; } - int removed = killMatchingEntities(radius, player, remover::createFunction); + int removed = killMatchingEntities(radius, actor, remover::createFunction); actor.print("Marked " + removed + (removed != 1 ? " entities" : " entity") + " for removal."); return removed; } - private int killMatchingEntities(Integer radius, Player player, Supplier func) throws IncompleteRegionException, MaxChangedBlocksException { + private int killMatchingEntities(Integer radius, Actor actor, Supplier func) throws IncompleteRegionException, + MaxChangedBlocksException { List visitors = new ArrayList<>(); - LocalSession session = null; - EditSession editSession = null; - if (player != null) { - session = we.getSessionManager().get(player); - BlockVector3 center = session.getPlacementPosition(player); - editSession = session.createEditSession(player); - List entities; - if (radius >= 0) { - CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius); - entities = editSession.getEntities(region); - } else { - entities = editSession.getEntities(); - } - visitors.add(new EntityVisitor(entities.iterator(), func.get())); + LocalSession session = we.getSessionManager().get(actor); + BlockVector3 center = session.getPlacementPosition(actor); + EditSession editSession = session.createEditSession(actor); + List entities; + if (radius >= 0) { + CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius); + entities = editSession.getEntities(region); } else { - Platform platform = we.getPlatformManager().queryCapability(Capability.WORLD_EDITING); - for (World world : platform.getWorlds()) { - List entities = world.getEntities(); - visitors.add(new EntityVisitor(entities.iterator(), func.get())); - } + entities = editSession.getEntities(); } + visitors.add(new EntityVisitor(entities.iterator(), func.get())); int killed = 0; for (EntityVisitor visitor : visitors) { @@ -473,10 +455,8 @@ public class UtilityCommands { killed += visitor.getAffected(); } - if (editSession != null) { - session.remember(editSession); - editSession.flushSession(); - } + session.remember(editSession); + editSession.flushSession(); return killed; } 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 25329885a..45041b587 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 @@ -30,6 +30,7 @@ import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.NoCapablePlatformException; import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.PlatformManager; import com.sk89q.worldedit.util.paste.ActorCallbackPaste; @@ -81,8 +82,12 @@ public class WorldEditCommands { actor.printDebug("----------- Capabilities -----------"); for (Capability capability : Capability.values()) { - Platform platform = pm.queryCapability(capability); - actor.printDebug(String.format("%s: %s", capability.name(), platform != null ? platform.getPlatformName() : "NONE")); + try { + Platform platform = pm.queryCapability(capability); + actor.printDebug(String.format("%s: %s", capability.name(), platform != null ? platform.getPlatformName() : "NONE")); + } catch (NoCapablePlatformException e) { + actor.printDebug(String.format("%s: %s", capability.name(), "NONE")); + } } } @@ -137,18 +142,18 @@ public class WorldEditCommands { name = "tz", desc = "Set your timezone for snapshots" ) - public void tz(Player player, LocalSession session, + public void tz(Actor actor, LocalSession session, @Arg(desc = "The timezone to set") String timezone) { try { ZoneId tz = ZoneId.of(timezone); session.setTimezone(tz); - player.print("Timezone set for this session to: " + tz.getDisplayName( + actor.print("Timezone set for this session to: " + tz.getDisplayName( TextStyle.FULL, Locale.ENGLISH )); - player.print("The current time in that timezone is: " + dateFormat.format(ZonedDateTime.now(tz))); + actor.print("The current time in that timezone is: " + dateFormat.format(ZonedDateTime.now(tz))); } catch (ZoneRulesException e) { - player.printError("Invalid timezone"); + actor.printError("Invalid timezone"); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java new file mode 100644 index 000000000..1841355fa --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/WorldConverter.java @@ -0,0 +1,81 @@ +/* + * 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.command.argument; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.util.formatting.text.Component; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.world.World; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.converter.ArgumentConverter; +import org.enginehub.piston.converter.ConversionResult; +import org.enginehub.piston.converter.FailedConversion; +import org.enginehub.piston.converter.SuccessfulConversion; +import org.enginehub.piston.inject.InjectedValueAccess; +import org.enginehub.piston.inject.Key; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class WorldConverter implements ArgumentConverter { + + public static void register(CommandManager commandManager) { + commandManager.registerConverter(Key.of(World.class), + new WorldConverter() + ); + } + + private final TextComponent choices; + + private WorldConverter() { + this.choices = TextComponent.of("any world"); + } + + @Override + public Component describeAcceptableArguments() { + return this.choices; + } + + private Stream getWorlds() { + return WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getWorlds().stream(); + } + + @Override + public List getSuggestions(String input) { + return getWorlds() + .map(World::getId) + .filter(world -> world.startsWith(input)) + .collect(Collectors.toList()); + } + + @Override + public ConversionResult convert(String s, InjectedValueAccess injectedValueAccess) { + World result = getWorlds() + .filter(world -> world.getId().equals(s)) + .findAny().orElse(null); + return result == null + ? FailedConversion.from(new IllegalArgumentException( + "Not a valid world: " + s)) + : SuccessfulConversion.fromSingle(result); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java index 43b5f1ea0..fcc83209c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/SelectionWand.java @@ -34,8 +34,8 @@ public class SelectionWand implements DoubleActionBlockTool { @Override public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { RegionSelector selector = session.getRegionSelector(player.getWorld()); - BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); + if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) { selector.explainPrimarySelection(player, session, blockPoint); } @@ -46,6 +46,7 @@ public class SelectionWand implements DoubleActionBlockTool { public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) { RegionSelector selector = session.getRegionSelector(player.getWorld()); BlockVector3 blockPoint = clicked.toVector().toBlockPoint(); + if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) { selector.explainSecondarySelection(player, session, blockPoint); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Entity.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Entity.java index 31bff6968..49084e069 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Entity.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Entity.java @@ -19,9 +19,9 @@ package com.sk89q.worldedit.entity; +import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.util.Faceted; -import com.sk89q.worldedit.util.Location; import javax.annotation.Nullable; @@ -33,7 +33,7 @@ import javax.annotation.Nullable; * instance of an entity, but a {@link BaseEntity} can be created from * this entity by calling {@link #getState()}.

    */ -public interface Entity extends Faceted { +public interface Entity extends Faceted, Locatable { /** * Get a copy of the entity's state. @@ -47,28 +47,6 @@ public interface Entity extends Faceted { @Nullable BaseEntity getState(); - /** - * Get the location of this entity. - * - * @return the location of the entity - */ - Location getLocation(); - - /** - * Sets the location of this entity. - * - * @param location the new location of the entity - * @return if the teleport worked - */ - boolean setLocation(Location location); - - /** - * Get the extent that this entity is on. - * - * @return the extent - */ - Extent getExtent(); - /** * Remove this entity from it container. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java index 3673d8842..8d0f3bba6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Player.java @@ -191,8 +191,12 @@ public interface Player extends Entity, Actor { * Get the point of the block that is being stood in. * * @return point + * @deprecated Use Locatable#getBlockLocation */ - Location getBlockIn(); + @Deprecated + default Location getBlockIn() { + return getBlockLocation(); + } /** * Get the point of the block that is being stood upon. @@ -281,13 +285,6 @@ public interface Player extends Entity, Actor { */ void setPosition(Vector3 pos, float pitch, float yaw); - /** - * Move the player. - * - * @param pos where to move them - */ - void setPosition(Vector3 pos); - /** * Sends a fake block to the client. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java new file mode 100644 index 000000000..8262d0696 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractNonPlayerActor.java @@ -0,0 +1,51 @@ +/* + * 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.extension.platform; + +import com.sk89q.worldedit.internal.cui.CUIEvent; + +import java.io.File; + +public abstract class AbstractNonPlayerActor implements Actor { + + @Override + public boolean canDestroyBedrock() { + return true; + } + + @Override + public boolean isPlayer() { + return false; + } + + @Override + public File openFileOpenDialog(String[] extensions) { + return null; + } + + @Override + public File openFileSaveDialog(String[] extensions) { + return null; + } + + @Override + public void dispatchCUIEvent(CUIEvent event) { + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java index 2054dc603..1b378b4c3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/AbstractPlayerActor.java @@ -151,12 +151,12 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public void findFreePosition() { - findFreePosition(getBlockIn()); + findFreePosition(getBlockLocation()); } @Override public boolean ascendLevel() { - final Location pos = getBlockIn(); + final Location pos = getBlockLocation(); final int x = pos.getBlockX(); int y = Math.max(0, pos.getBlockY()); final int z = pos.getBlockZ(); @@ -197,7 +197,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public boolean descendLevel() { - final Location pos = getBlockIn(); + final Location pos = getBlockLocation(); final int x = pos.getBlockX(); int y = Math.max(0, pos.getBlockY() - 1); final int z = pos.getBlockZ(); @@ -247,7 +247,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public boolean ascendToCeiling(int clearance, boolean alwaysGlass) { - Location pos = getBlockIn(); + Location pos = getBlockLocation(); int x = pos.getBlockX(); int initialY = Math.max(0, pos.getBlockY()); int y = Math.max(0, pos.getBlockY() + 2); @@ -287,7 +287,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { @Override public boolean ascendUpwards(int distance, boolean alwaysGlass) { - final Location pos = getBlockIn(); + final Location pos = getBlockLocation(); final int x = pos.getBlockX(); final int initialY = Math.max(0, pos.getBlockY()); int y = Math.max(0, pos.getBlockY() + 1); @@ -345,13 +345,6 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable { protected void setFlying(boolean flying) { } - - @Override - public Location getBlockIn() { - final Location location = getLocation(); - return location.setPosition(location.toVector().floor()); - } - @Override public Location getBlockOn() { final Location location = getLocation(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Locatable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Locatable.java new file mode 100644 index 000000000..cc25ab5c7 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Locatable.java @@ -0,0 +1,69 @@ +/* + * 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.extension.platform; + +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.util.Location; + +public interface Locatable { + + /** + * Get the location of this actor. + * + * @return the location of the actor + */ + Location getLocation(); + + /** + * Get the location of this actor in block coordinates. + * + * @return the block location of the actor + */ + default Location getBlockLocation() { + Location location = getLocation(); + return location.setPosition(location.toVector().floor()); + } + + /** + * Sets the location of this actor. + * + * @param location the new location of the actor + * @return if the teleport succeeded + */ + boolean setLocation(Location location); + + /** + * Sets the position of this actor. + * + * @param pos where to move them + */ + default void setPosition(Vector3 pos) { + setLocation(new Location(getExtent(), pos)); + } + + /** + * Get the extent that this actor is in. + * + * @return the extent + */ + Extent getExtent(); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 673bb2a17..296dfd1c3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.extension.platform; +import static com.google.common.base.Preconditions.checkNotNull; + import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.reflect.TypeToken; @@ -26,6 +28,7 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MissingWorldException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.command.ApplyBrushCommands; import com.sk89q.worldedit.command.BiomeCommands; @@ -79,6 +82,7 @@ import com.sk89q.worldedit.command.argument.FactoryConverter; import com.sk89q.worldedit.command.argument.RegionFactoryConverter; import com.sk89q.worldedit.command.argument.RegistryConverter; import com.sk89q.worldedit.command.argument.VectorConverter; +import com.sk89q.worldedit.command.argument.WorldConverter; import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter; import com.sk89q.worldedit.command.util.PermissionCondition; import com.sk89q.worldedit.command.util.SubCommandPermissionCondition; @@ -137,8 +141,6 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.google.common.base.Preconditions.checkNotNull; - /** * Handles the registration and invocation of commands. * @@ -218,34 +220,55 @@ public final class PlatformCommandManager { BooleanConverter.register(commandManager); EntityRemoverConverter.register(commandManager); RegionFactoryConverter.register(commandManager); + WorldConverter.register(commandManager); } private void registerAlwaysInjectedValues() { globalInjectedValues.injectValue(Key.of(Region.class, Selection.class), - context -> { - LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) - .orElseThrow(() -> new IllegalStateException("No LocalSession")); - return context.injectedValue(Key.of(Player.class)) - .map(player -> { - try { - return localSession.getSelection(player.getWorld()); - } catch (IncompleteRegionException e) { - exceptionConverter.convert(e); - throw new AssertionError("Should have thrown a new exception."); - } - }); - }); + context -> { + LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("No LocalSession")); + return context.injectedValue(Key.of(World.class)) + .map(world -> { + try { + return localSession.getSelection(world); + } catch (IncompleteRegionException e) { + exceptionConverter.convert(e); + throw new AssertionError("Should have thrown a new exception.", e); + } + }); + }); globalInjectedValues.injectValue(Key.of(EditSession.class), - context -> { - LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) - .orElseThrow(() -> new IllegalStateException("No LocalSession")); - return context.injectedValue(Key.of(Player.class)) - .map(player -> { - EditSession editSession = localSession.createEditSession(player); - editSession.enableStandardMode(); - return editSession; - }); - }); + context -> { + LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("No LocalSession")); + return context.injectedValue(Key.of(Actor.class)) + .map(actor -> { + EditSession editSession = localSession.createEditSession(actor); + editSession.enableStandardMode(); + return editSession; + }); + }); + globalInjectedValues.injectValue(Key.of(World.class), + context -> { + LocalSession localSession = context.injectedValue(Key.of(LocalSession.class)) + .orElseThrow(() -> new IllegalStateException("No LocalSession")); + return context.injectedValue(Key.of(Actor.class)) + .map(actor -> { + try { + if (localSession.hasWorldOverride()) { + return localSession.getWorldOverride(); + } else if (actor instanceof Locatable && ((Locatable) actor).getExtent() instanceof World) { + return (World) ((Locatable) actor).getExtent(); + } else { + throw new MissingWorldException(); + } + } catch (MissingWorldException e) { + exceptionConverter.convert(e); + throw new AssertionError("Should have thrown a new exception.", e); + } + }); + }); } private void registerSubCommands(String name, List aliases, String desc, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java index aeaf07e85..6994442fe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/Clipboard.java @@ -61,7 +61,7 @@ public interface Clipboard extends Extent { /** * Returns true if the clipboard has biome data. This can be checked since {@link Extent#getBiome(BlockVector2)} - * strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes.OCEAN} instead of {@code null} + * strongly suggests returning {@link com.sk89q.worldedit.world.biome.BiomeTypes#OCEAN} instead of {@code null} * if biomes aren't present. However, it might not be desired to set areas to ocean if the clipboard is defaulting * to ocean, instead of having biomes explicitly set. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java index 94f76fe5f..ed681655b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/ClipboardReader.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import java.io.Closeable; import java.io.IOException; +import java.util.OptionalInt; /** * Reads {@code Clipboard}s. @@ -39,4 +40,12 @@ public interface ClipboardReader extends Closeable { */ Clipboard read() throws IOException; + /** + * Get the DataVersion from a file (if possible). + * + * @return The data version, or empty + */ + default OptionalInt getDataVersion() { + return OptionalInt.empty(); + } } 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 890d02943..d4e517813 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 @@ -60,6 +60,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.OptionalInt; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -72,6 +73,7 @@ public class SpongeSchematicReader extends NBTSchematicReader { private static final Logger log = LoggerFactory.getLogger(SpongeSchematicReader.class); private final NBTInputStream inputStream; private DataFixer fixer = null; + private int schematicVersion = -1; private int dataVersion = -1; /** @@ -86,25 +88,18 @@ public class SpongeSchematicReader extends NBTSchematicReader { @Override public Clipboard read() 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 + CompoundTag schematicTag = getBaseTag(); Map schematic = schematicTag.getValue(); - int version = requireTag(schematic, "Version", IntTag.class).getValue(); final Platform platform = WorldEdit.getInstance().getPlatformManager() .queryCapability(Capability.WORLD_EDITING); int liveDataVersion = platform.getDataVersion(); - if (version == 1) { + if (schematicVersion == 1) { dataVersion = 1631; // this is a relatively safe assumption unless someone imports a schematic from 1.12, e.g. sponge 7.1- fixer = platform.getDataFixer(); return readVersion1(schematicTag); - } else if (version == 2) { + } else if (schematicVersion == 2) { dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue(); if (dataVersion > liveDataVersion) { log.warn("Schematic was made in a newer Minecraft version ({} > {}). Data may be incompatible.", @@ -126,6 +121,36 @@ public class SpongeSchematicReader extends NBTSchematicReader { throw new IOException("This schematic version is currently not supported"); } + @Override + public OptionalInt getDataVersion() { + try { + CompoundTag schematicTag = getBaseTag(); + Map schematic = schematicTag.getValue(); + if (schematicVersion == 1) { + return OptionalInt.of(1631); + } else if (schematicVersion == 2) { + return OptionalInt.of(requireTag(schematic, "DataVersion", IntTag.class).getValue()); + } + return OptionalInt.empty(); + } catch (IOException e) { + return OptionalInt.empty(); + } + } + + 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 + Map schematic = schematicTag.getValue(); + + schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue(); + return schematicTag; + } + private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOException { BlockVector3 origin; Region region; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java index f97123292..5dd010c61 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.world.World; import org.enginehub.piston.CommandParameters; import org.enginehub.piston.gen.CommandCallListener; import org.enginehub.piston.inject.Key; @@ -72,18 +73,18 @@ public class CommandLoggingHandler implements CommandCallListener, AutoCloseable logMode = loggingAnnotation.value(); } - Optional playerOpt = parameters.injectedValue(Key.of(Actor.class)) - .filter(Player.class::isInstance) - .map(Player.class::cast); + Optional playerOpt = parameters.injectedValue(Key.of(Actor.class)); + Optional worldOpt = parameters.injectedValue(Key.of(World.class)); - if (!playerOpt.isPresent()) { + if (!playerOpt.isPresent() || !worldOpt.isPresent()) { return; } - Player player = playerOpt.get(); + Actor actor = playerOpt.get(); + World world = worldOpt.get(); - builder.append("WorldEdit: ").append(player.getName()); - builder.append(" (in \"").append(player.getWorld().getName()).append("\")"); + builder.append("WorldEdit: ").append(actor.getName()); + builder.append(" (in \"").append(world.getName()).append("\")"); builder.append(": ").append(parameters.getMetadata().getCalledName()); @@ -93,14 +94,15 @@ public class CommandLoggingHandler implements CommandCallListener, AutoCloseable parameters.getMetadata().getArguments().stream() ).collect(Collectors.joining(" "))); - if (logMode != null) { + if (logMode != null && actor instanceof Player) { + Player player = (Player) actor; Vector3 position = player.getLocation().toVector(); - LocalSession session = worldEdit.getSessionManager().get(player); + LocalSession session = worldEdit.getSessionManager().get(actor); switch (logMode) { case PLACEMENT: try { - position = session.getPlacementPosition(player).toVector3(); + position = session.getPlacementPosition(actor).toVector3(); } catch (IncompleteRegionException e) { break; } @@ -121,7 +123,7 @@ public class CommandLoggingHandler implements CommandCallListener, AutoCloseable case REGION: try { builder.append(" - Region: ") - .append(session.getSelection(player.getWorld())); + .append(session.getSelection(world)); } catch (IncompleteRegionException e) { break; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java index 5270cab87..9f6a40fe0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/exception/WorldEditExceptionConverter.java @@ -27,6 +27,7 @@ import com.sk89q.worldedit.InvalidItemException; import com.sk89q.worldedit.MaxBrushRadiusException; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxRadiusException; +import com.sk89q.worldedit.MissingWorldException; import com.sk89q.worldedit.UnknownDirectionException; import com.sk89q.worldedit.UnknownItemException; import com.sk89q.worldedit.WorldEdit; @@ -81,6 +82,11 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper { throw newCommandException("Make a region selection first.", e); } + @ExceptionMatch + public void convert(MissingWorldException e) throws CommandException { + throw newCommandException("You need to provide a world (Try //world)", e); + } + @ExceptionMatch public void convert(UnknownItemException e) throws CommandException { throw newCommandException("Block name '" + e.getID() + "' was not recognized.", e); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java index 201cac554..fb4b8f9fd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/AbstractWorld.java @@ -33,6 +33,8 @@ import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.weather.WeatherType; +import com.sk89q.worldedit.world.weather.WeatherTypes; import java.nio.file.Path; import java.util.PriorityQueue; @@ -133,6 +135,24 @@ public abstract class AbstractWorld implements World { return null; } + @Override + public WeatherType getWeather() { + return WeatherTypes.CLEAR; + } + + @Override + public long getRemainingWeatherDuration() { + return 0; + } + + @Override + public void setWeather(WeatherType weatherType) { + } + + @Override + public void setWeather(WeatherType weatherType, long duration) { + } + private class QueuedEffect implements Comparable { private final Vector3 position; private final BlockType blockType; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java index f8a286dfd..7f41afded 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java @@ -61,6 +61,11 @@ public class NullWorld extends AbstractWorld { return "null"; } + @Override + public String getId() { + return "null"; + } + @Override public > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException { return false; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index 471279281..8d49c111b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.block.BlockState; @@ -44,7 +45,7 @@ import java.nio.file.Path; /** * Represents a world (dimension). */ -public interface World extends Extent { +public interface World extends Extent, Keyed { /** * Get the name of the world. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java index 0de14a17c..7f794b021 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/CategoryRegistry.java @@ -37,5 +37,7 @@ public interface CategoryRegistry { */ Set getCategorisedByName(String category); - Set getAll(final Category category); + default Set getAll(final Category category) { + return getCategorisedByName(category.getId()); + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullBlockCategoryRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullBlockCategoryRegistry.java index 4484d67d2..3e0322ca6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullBlockCategoryRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullBlockCategoryRegistry.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.world.registry; -import com.sk89q.worldedit.registry.Category; import com.sk89q.worldedit.world.block.BlockType; import java.util.Collections; @@ -31,9 +30,4 @@ public class NullBlockCategoryRegistry implements BlockCategoryRegistry { public Set getCategorisedByName(String category) { return Collections.emptySet(); } - - @Override - public Set getAll(final Category category) { - return Collections.emptySet(); - } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullItemCategoryRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullItemCategoryRegistry.java index 8eb5d9ee6..070e2fcfa 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullItemCategoryRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullItemCategoryRegistry.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.world.registry; -import com.sk89q.worldedit.registry.Category; import com.sk89q.worldedit.world.item.ItemType; import java.util.Collections; @@ -31,9 +30,4 @@ public class NullItemCategoryRegistry implements ItemCategoryRegistry { public Set getCategorisedByName(String category) { return Collections.emptySet(); } - - @Override - public Set getAll(final Category category) { - return Collections.emptySet(); - } } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockCategoryRegistry.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockCategoryRegistry.java index bbf6ffbd3..87a72c9f6 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockCategoryRegistry.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricBlockCategoryRegistry.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.fabric; -import com.sk89q.worldedit.registry.Category; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; import net.minecraft.tag.BlockTags; @@ -38,9 +37,4 @@ public class FabricBlockCategoryRegistry implements BlockCategoryRegistry { .map(Tag::values).orElse(Collections.emptySet()) .stream().map(FabricAdapter::adapt).collect(Collectors.toSet()); } - - @Override - public Set getAll(Category category) { - return getCategorisedByName(category.getId()); - } } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemCategoryRegistry.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemCategoryRegistry.java index e8ec3e43f..bcdc7a0c2 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemCategoryRegistry.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricItemCategoryRegistry.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.fabric; -import com.sk89q.worldedit.registry.Category; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; import net.minecraft.tag.ItemTags; @@ -38,9 +37,4 @@ public class FabricItemCategoryRegistry implements ItemCategoryRegistry { .map(Tag::values).orElse(Collections.emptySet()) .stream().map(FabricAdapter::adapt).collect(Collectors.toSet()); } - - @Override - public Set getAll(Category category) { - return getCategorisedByName(category.getId()); - } } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java index 93d14b753..886523df5 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWorld.java @@ -100,6 +100,7 @@ import java.lang.ref.WeakReference; import java.nio.file.Path; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Optional; import java.util.OptionalInt; import java.util.Random; @@ -168,6 +169,13 @@ public class FabricWorld extends AbstractWorld { return getWorld().getLevelProperties().getLevelName(); } + @Override + public String getId() { + return getWorld().getLevelProperties().getLevelName() + .replace(" ", "_").toLowerCase(Locale.ROOT) + + getWorld().dimension.getType().getSuffix(); + } + @Override public Path getStoragePath() { final World world = getWorld(); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java index 85fdc4fea..0290dbdd6 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeBlockCategoryRegistry.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.forge; -import com.sk89q.worldedit.registry.Category; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; import net.minecraft.tags.BlockTags; @@ -38,9 +37,4 @@ public class ForgeBlockCategoryRegistry implements BlockCategoryRegistry { .map(Tag::getAllElements).orElse(Collections.emptySet()) .stream().map(ForgeAdapter::adapt).collect(Collectors.toSet()); } - - @Override - public Set getAll(Category category) { - return getCategorisedByName(category.getId()); - } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java index a12fb10c3..8dd4bbb99 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeItemCategoryRegistry.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.forge; -import com.sk89q.worldedit.registry.Category; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; import net.minecraft.tags.ItemTags; @@ -38,9 +37,4 @@ public class ForgeItemCategoryRegistry implements ItemCategoryRegistry { .map(Tag::getAllElements).orElse(Collections.emptySet()) .stream().map(ForgeAdapter::adapt).collect(Collectors.toSet()); } - - @Override - public Set getAll(Category category) { - return getCategorisedByName(category.getId()); - } } diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java index 6e034e863..ea6fea11d 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWorld.java @@ -93,6 +93,7 @@ import net.minecraft.world.server.ServerChunkProvider; import net.minecraft.world.server.ServerWorld; import net.minecraft.world.storage.SaveHandler; import net.minecraft.world.storage.WorldInfo; +import net.minecraftforge.common.DimensionManager; import javax.annotation.Nullable; import java.io.File; @@ -169,6 +170,11 @@ public class ForgeWorld extends AbstractWorld { return getWorld().getWorldInfo().getWorldName(); } + @Override + public String getId() { + return DimensionManager.getRegistry().getKey(getWorld().dimension.getType()).toString(); + } + @Override public Path getStoragePath() { final World world = getWorld(); diff --git a/worldedit-libs/cli/build.gradle.kts b/worldedit-libs/cli/build.gradle.kts new file mode 100644 index 000000000..388618cea --- /dev/null +++ b/worldedit-libs/cli/build.gradle.kts @@ -0,0 +1 @@ +applyLibrariesConfiguration() diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java index 04b1961ff..d899c7ae1 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorld.java @@ -60,6 +60,7 @@ import java.lang.ref.WeakReference; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Optional; @@ -117,6 +118,12 @@ public abstract class SpongeWorld extends AbstractWorld { return getWorld().getName(); } + @Override + public String getId() { + return getName().replace(" ", "_").toLowerCase(Locale.ROOT) + + getWorld().getDimension().getType().getName().toLowerCase(Locale.ROOT); + } + @Override public Path getStoragePath() { return getWorld().getDirectory(); From 7af397bd56291b579f2c29d8cbde84ec001e6058 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 26 Aug 2019 00:17:22 -0700 Subject: [PATCH 325/366] [Doctools] Fix //rotate description quoting --- worldedit-core/doctools/build.gradle.kts | 6 ++++++ .../sk89q/worldedit/internal/util/DocumentationPrinter.kt | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/worldedit-core/doctools/build.gradle.kts b/worldedit-core/doctools/build.gradle.kts index 66aa2285f..0fba2e7f2 100644 --- a/worldedit-core/doctools/build.gradle.kts +++ b/worldedit-core/doctools/build.gradle.kts @@ -2,6 +2,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { kotlin("jvm") version "1.3.41" + application } applyCommonConfiguration() @@ -10,6 +11,11 @@ tasks.withType { kotlinOptions.jvmTarget = "1.8" } +application.mainClassName = "com.sk89q.worldedit.internal.util.DocumentationPrinter" +tasks.named("run") { + workingDir = rootProject.projectDir +} + dependencies { "implementation"(project(":worldedit-libs:core:ap")) "implementation"(project(":worldedit-core")) diff --git a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt index dd06e46a3..011ae4b05 100644 --- a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt @@ -60,7 +60,9 @@ class DocumentationPrinter private constructor() { private suspend inline fun SequenceScope.yieldAllCommandsIn() { val sourceFile = Paths.get("worldedit-core/src/main/java/" + T::class.qualifiedName!!.replace('.', '/') + ".java") - require(Files.exists(sourceFile)) { "Source not found for ${T::class.qualifiedName}"} + require(Files.exists(sourceFile)) { + "Source not found for ${T::class.qualifiedName}, looked at ${sourceFile.toAbsolutePath()}" + } Files.newBufferedReader(sourceFile).useLines { lines -> var inCommand = false for (line in lines) { @@ -267,7 +269,7 @@ Other Permissions """.trimMargin()) cmdOutput.appendln() for ((k, v) in entries) { - val rstSafe = v.replace("\"", "\\\"").replace("\n", "\n" + " ".repeat(2)) + val rstSafe = v.trim().replace("\"", "\\\"").replace("\n", "\n" + " ".repeat(2)) .lineSequence().map { line -> line.ifBlank { "" } }.joinToString(separator = "\n") cmdOutput.append(" ".repeat(2)) .append(k) From 45bfa0d140e03206ba30fe3a141360063edbb2cb Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 26 Aug 2019 00:45:08 -0700 Subject: [PATCH 326/366] [Doctools] Add command-topic for CSS markup --- .../com/sk89q/worldedit/internal/util/DocumentationPrinter.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt index 011ae4b05..0e76154c6 100644 --- a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt @@ -262,7 +262,8 @@ Other Permissions postfix = ")", transform = { "``$prefix$it``" }) } - cmdOutput.appendln().appendln() + cmdOutput.appendln() + cmdOutput.appendln(" :class: command-topic").appendln() cmdOutput.appendln(""" | .. csv-table:: | :widths: 8, 15 From 44bffc5a86f71329bfe5d585af706021171ccf2c Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Tue, 27 Aug 2019 21:54:53 +1000 Subject: [PATCH 327/366] Use https for the pastebin service --- .../java/com/sk89q/worldedit/util/paste/EngineHubPaste.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java index ab8ebe029..3a5e01b6e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/paste/EngineHubPaste.java @@ -54,7 +54,7 @@ public class EngineHubPaste implements Paster { form.add("content", content); form.add("from", "enginehub"); - URL url = HttpRequest.url("http://paste.enginehub.org/paste"); + URL url = HttpRequest.url("https://paste.enginehub.org/paste"); String result = HttpRequest.post(url) .bodyForm(form) .execute() From 299d703f248e6b844721b8273cbcf38dbfbd50a2 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Thu, 29 Aug 2019 19:58:00 -0700 Subject: [PATCH 328/366] [Doctools] Fix //expand listing, ensure no missed commands --- .../sk89q/worldedit/internal/util/DocumentationPrinter.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt index 0e76154c6..c6b94b86b 100644 --- a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt @@ -57,6 +57,7 @@ class DocumentationPrinter private constructor() { .map { it.name to it }.toList().toMap() private val cmdOutput = StringBuilder() private val permsOutput = StringBuilder() + private val matchedCommands = mutableSetOf() private suspend inline fun SequenceScope.yieldAllCommandsIn() { val sourceFile = Paths.get("worldedit-core/src/main/java/" + T::class.qualifiedName!!.replace('.', '/') + ".java") @@ -93,7 +94,7 @@ class DocumentationPrinter private constructor() { dumpSection("Selection Commands") { yieldAllCommandsIn() - yieldAllCommandsIn() + yield("/expand") } dumpSection("Region Commands") { @@ -144,6 +145,9 @@ class DocumentationPrinter private constructor() { } writeFooter() + + val missingCommands = commands.keys.filterNot { it in matchedCommands } + require(missingCommands.isEmpty()) { "Missing commands: $missingCommands" } } private fun writeHeader() { @@ -214,6 +218,7 @@ Other Permissions val prefix = TextConfig.getCommandPrefix() val commands = sequence(addCommandNames).map { this.commands.getValue(it) }.toList() + matchedCommands.addAll(commands.map { it.name }) cmdsToPerms(commands, prefix) From a73a45ce43c50f8814553dbdc47e59ec256f7a19 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 31 Aug 2019 16:30:51 +1000 Subject: [PATCH 329/366] Create parser context data for factory converter in non-user-mode --- .../com/sk89q/worldedit/command/argument/FactoryConverter.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java index 8b5a56f0c..8e5b0d9e8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/FactoryConverter.java @@ -110,6 +110,9 @@ public class FactoryConverter implements ArgumentConverter { parserContext.setWorld((World) extent); } parserContext.setExtent(new RequestExtent()); + } else if (session.hasWorldOverride()) { + parserContext.setWorld(session.getWorldOverride()); + parserContext.setExtent(new RequestExtent()); } parserContext.setSession(session); parserContext.setRestricted(true); From 8fdd15f357a6dfbe0d08f30f7afc4b047df39f78 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 1 Sep 2019 20:11:34 -0700 Subject: [PATCH 330/366] [CLI,Libs] Minimize CLI, exclude slf4j from libs --- buildSrc/src/main/kotlin/LibsConfig.kt | 1 + worldedit-cli/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/LibsConfig.kt b/buildSrc/src/main/kotlin/LibsConfig.kt index c2754d487..558d68ae4 100644 --- a/buildSrc/src/main/kotlin/LibsConfig.kt +++ b/buildSrc/src/main/kotlin/LibsConfig.kt @@ -33,6 +33,7 @@ fun Project.applyLibrariesConfiguration() { exclude(dependency("com.google.guava:guava")) exclude(dependency("com.google.code.gson:gson")) exclude(dependency("org.checkerframework:checker-qual")) + exclude(dependency("org.slf4j:slf4j-api")) } relocate("net.kyori.text", "com.sk89q.worldedit.util.formatting.text") diff --git a/worldedit-cli/build.gradle.kts b/worldedit-cli/build.gradle.kts index ea047b641..ab563127c 100644 --- a/worldedit-cli/build.gradle.kts +++ b/worldedit-cli/build.gradle.kts @@ -24,7 +24,7 @@ tasks.named("shadowJar") { include { true } } minimize { - exclude { true } + exclude(dependency("org.apache.logging.log4j:log4j-core")) } } From fa364dd7389abe48a9e3291a05db49fc4cb25254 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 7 Sep 2019 21:59:13 -0700 Subject: [PATCH 331/366] [Forge] Update FG + Forge --- buildSrc/build.gradle.kts | 2 +- worldedit-forge/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 1d1da51c1..101cff2aa 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -32,5 +32,5 @@ dependencies { implementation("net.ltgt.apt-idea:net.ltgt.apt-idea.gradle.plugin:0.21") implementation("org.jfrog.buildinfo:build-info-extractor-gradle:4.9.7") implementation("gradle.plugin.org.spongepowered:spongegradle:0.9.0") - implementation("net.minecraftforge.gradle:ForgeGradle:3.0.130") + implementation("net.minecraftforge.gradle:ForgeGradle:3.0.141") } diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index 1c952f5bc..a65e609bb 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -13,7 +13,7 @@ applyShadowConfiguration() val minecraftVersion = "1.14.4" val mappingsMinecraftVersion = "1.14.3" -val forgeVersion = "28.0.45" +val forgeVersion = "28.0.95" configurations.all { resolutionStrategy { From 0e9fee3b6044bd2bde3f5c5af04ff52bee636ff6 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 8 Sep 2019 17:42:57 -0700 Subject: [PATCH 332/366] Add /tool back, deprecate global tool commands --- .../sk89q/worldedit/command/ToolCommands.java | 75 ++++++++++++++++++- .../platform/PlatformCommandManager.java | 11 +-- .../internal/command/CommandUtil.java | 63 ++++++++++++++++ 3 files changed, 137 insertions(+), 12 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 5c8de085c..f3ef732b4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.command; +import com.google.common.collect.Collections2; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.WorldEdit; @@ -38,16 +39,82 @@ import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.internal.command.CommandRegistrationHandler; +import com.sk89q.worldedit.internal.command.CommandUtil; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.TreeGenerator; +import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.item.ItemType; +import org.enginehub.piston.CommandManager; +import org.enginehub.piston.CommandManagerService; +import org.enginehub.piston.CommandMetadata; +import org.enginehub.piston.CommandParameters; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; +import org.enginehub.piston.part.SubCommandPart; + +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) public class ToolCommands { + + public static void register(CommandRegistrationHandler registration, + CommandManager commandManager, + CommandManagerService commandManagerService, + WorldEdit worldEdit) { + // Collect the tool commands + CommandManager collect = commandManagerService.newCommandManager(); + + registration.register( + collect, + ToolCommandsRegistration.builder(), + new ToolCommands(worldEdit) + ); + + // Register deprecated global commands + Set commands = collect.getAllCommands() + .collect(Collectors.toSet()); + for (org.enginehub.piston.Command command : commands) { + commandManager.register(CommandUtil.deprecate( + command, "Using global tool names is deprecated " + + "and will be removed in WorldEdit 8", ToolCommands::asNonGlobal + )); + } + + // Remove aliases with / in them, since it doesn't make sense for sub-commands. + Set nonGlobalCommands = commands.stream() + .map(command -> + command.toBuilder().aliases( + Collections2.filter(command.getAliases(), alias -> !alias.startsWith("/")) + ).build() + ) + .collect(Collectors.toSet()); + commandManager.register("tool", command -> { + command.addPart(SubCommandPart.builder( + TranslatableComponent.of("tool"), + TextComponent.of("The tool to bind") + ) + .withCommands(nonGlobalCommands) + .required() + .build()); + command.description(TextComponent.of("Binds a tool to the item in your hand")); + }); + } + + private static String asNonGlobal(org.enginehub.piston.Command oldCommand, + CommandParameters oldParameters) { + String name = Optional.ofNullable(oldParameters.getMetadata()) + .map(CommandMetadata::getCalledName) + .filter(n -> !n.startsWith("/")) + .orElseGet(oldCommand::getName); + return "/tool " + name; + } + private final WorldEdit we; public ToolCommands(WorldEdit we) { @@ -65,8 +132,8 @@ public class ToolCommands { } @Command( - name = "/selwand", - aliases = "selwand", + name = "selwand", + aliases = "/selwand", desc = "Selection wand tool" ) @CommandPermissions("worldedit.setwand") @@ -78,8 +145,8 @@ public class ToolCommands { } @Command( - name = "/navwand", - aliases = "navwand", + name = "navwand", + aliases = "/navwand", desc = "Navigation wand tool" ) @CommandPermissions("worldedit.setwand") diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 296dfd1c3..2913a277d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -19,8 +19,6 @@ package com.sk89q.worldedit.extension.platform; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.reflect.TypeToken; @@ -64,7 +62,6 @@ import com.sk89q.worldedit.command.SnapshotUtilCommandsRegistration; import com.sk89q.worldedit.command.SuperPickaxeCommands; import com.sk89q.worldedit.command.SuperPickaxeCommandsRegistration; import com.sk89q.worldedit.command.ToolCommands; -import com.sk89q.worldedit.command.ToolCommandsRegistration; import com.sk89q.worldedit.command.ToolUtilCommands; import com.sk89q.worldedit.command.ToolUtilCommandsRegistration; import com.sk89q.worldedit.command.UtilityCommands; @@ -141,6 +138,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; +import static com.google.common.base.Preconditions.checkNotNull; + /** * Handles the registration and invocation of commands. * @@ -399,11 +398,7 @@ public final class PlatformCommandManager { SnapshotUtilCommandsRegistration.builder(), new SnapshotUtilCommands(worldEdit) ); - this.registration.register( - commandManager, - ToolCommandsRegistration.builder(), - new ToolCommands(worldEdit) - ); + ToolCommands.register(registration, commandManager, commandManagerService, worldEdit); this.registration.register( commandManager, ToolUtilCommandsRegistration.builder(), diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java index bdcd8e541..d1690fc24 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java @@ -21,11 +21,17 @@ package com.sk89q.worldedit.internal.command; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.PlatformCommandManager; import com.sk89q.worldedit.internal.util.Substring; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; +import com.sk89q.worldedit.util.formatting.text.format.TextColor; +import com.sk89q.worldedit.util.formatting.text.format.TextDecoration; import org.enginehub.piston.Command; +import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.NoInputCommandParameters; import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.Key; @@ -43,6 +49,63 @@ import static java.util.stream.Collectors.toList; public class CommandUtil { + private static Component makeDeprecatedFooter(Component newCommand) { + return TextComponent.builder("This command is deprecated. Use ", TextColor.GOLD) + .decoration(TextDecoration.ITALIC, true) + .append(newCommand) + .append(" instead.") + .build(); + } + + public interface NewCommandGenerator { + + String newCommand(Command oldCommand, CommandParameters oldParameters); + + } + + public static Command deprecate(Command command, String reason, + NewCommandGenerator newCommandGenerator) { + Component deprecatedWarning = makeDeprecatedFooter( + newCommandSuggestion(newCommandGenerator, + NoInputCommandParameters.builder().build(), + command) + ); + return command.toBuilder() + .action(parameters -> + deprecatedCommandWarning(parameters, command, reason, newCommandGenerator)) + .footer(command.getFooter() + .map(existingFooter -> existingFooter + .append(TextComponent.newline()).append(deprecatedWarning)) + .orElse(deprecatedWarning)) + .build(); + } + + private static int deprecatedCommandWarning( + CommandParameters parameters, + Command command, + String reason, + NewCommandGenerator generator + ) throws Exception { + parameters.injectedValue(Key.of(Actor.class)) + .ifPresent(actor -> { + Component suggestion = newCommandSuggestion(generator, parameters, command); + actor.print(TextComponent.of(reason + ". Please use ", TextColor.GOLD) + .append(suggestion) + .append(TextComponent.of(" instead.")) + ); + }); + return command.getAction().run(parameters); + } + + private static Component newCommandSuggestion(NewCommandGenerator generator, + CommandParameters parameters, + Command command) { + String suggestedCommand = generator.newCommand(command, parameters); + return TextComponent.of(suggestedCommand) + .decoration(TextDecoration.UNDERLINED, true) + .clickEvent(ClickEvent.suggestCommand(suggestedCommand)); + } + public static Map getSubCommands(Command currentCommand) { return currentCommand.getParts().stream() .filter(p -> p instanceof SubCommandPart) From ba26d788af7274a9abba5543226d5bcfd558ba2d Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 9 Sep 2019 18:13:57 -0700 Subject: [PATCH 333/366] Add `/brush none` and unbind aliases --- .../sk89q/worldedit/command/BrushCommands.java | 9 +++++++++ .../sk89q/worldedit/command/ToolCommands.java | 18 +++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) 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 9b8e35dae..e15159af6 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 @@ -82,6 +82,15 @@ public class BrushCommands { this.worldEdit = worldEdit; } + @Command( + name = "none", + aliases = "unbind", + desc = "Unbind a bound brush from your current item" + ) + void none(Player player, LocalSession session) throws WorldEditException { + ToolCommands.setToolNone(player, session, "Brush"); + } + @Command( name = "sphere", aliases = { "s" }, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index f3ef732b4..29c05676c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -30,6 +30,7 @@ import com.sk89q.worldedit.command.tool.BlockReplacer; import com.sk89q.worldedit.command.tool.DistanceWand; import com.sk89q.worldedit.command.tool.FloatingTreeRemover; import com.sk89q.worldedit.command.tool.FloodFillTool; +import com.sk89q.worldedit.command.tool.InvalidToolBindException; import com.sk89q.worldedit.command.tool.LongRangeBuildTool; import com.sk89q.worldedit.command.tool.NavigationWand; import com.sk89q.worldedit.command.tool.QueryTool; @@ -80,6 +81,12 @@ public class ToolCommands { Set commands = collect.getAllCommands() .collect(Collectors.toSet()); for (org.enginehub.piston.Command command : commands) { + if (command.getAliases().contains("unbind")) { + // Don't register new /tool unbind alias + command = command.toBuilder().aliases( + Collections2.filter(command.getAliases(), alias -> !"unbind".equals(alias)) + ).build(); + } commandManager.register(CommandUtil.deprecate( command, "Using global tool names is deprecated " + "and will be removed in WorldEdit 8", ToolCommands::asNonGlobal @@ -115,6 +122,12 @@ public class ToolCommands { return "/tool " + name; } + static void setToolNone(Player player, LocalSession session, String type) + throws InvalidToolBindException { + session.setTool(player.getItemInHand(HandSide.MAIN_HAND).getType(), null); + player.print(type + " unbound from your current item."); + } + private final WorldEdit we; public ToolCommands(WorldEdit we) { @@ -123,12 +136,11 @@ public class ToolCommands { @Command( name = "none", + aliases = "unbind", desc = "Unbind a bound tool from your current item" ) public void none(Player player, LocalSession session) throws WorldEditException { - - session.setTool(player.getItemInHand(HandSide.MAIN_HAND).getType(), null); - player.print("Tool unbound from your current item."); + setToolNone(player, session, "Tool"); } @Command( From 23ca70e49afe9132a738ff305bbbde194c493a0f Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 14 Sep 2019 01:06:49 -0700 Subject: [PATCH 334/366] [Forge] Update to Recommended Forge, newer mappings --- worldedit-forge/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index a65e609bb..e71c04295 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -13,7 +13,7 @@ applyShadowConfiguration() val minecraftVersion = "1.14.4" val mappingsMinecraftVersion = "1.14.3" -val forgeVersion = "28.0.95" +val forgeVersion = "28.1.0" configurations.all { resolutionStrategy { @@ -31,7 +31,7 @@ dependencies { configure { mappings(mapOf( "channel" to "snapshot", - "version" to "20190801-$mappingsMinecraftVersion" + "version" to "20190913-$mappingsMinecraftVersion" )) runs { From 44dc926c49b009e55be94267f5a9994367f4103e Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 19 Sep 2019 20:53:47 -0400 Subject: [PATCH 335/366] Fix console command usage. --- .../command/CommandLoggingHandler.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java index 5dd010c61..9f2335d57 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandLoggingHandler.java @@ -28,6 +28,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.world.World; import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.gen.CommandCallListener; import org.enginehub.piston.inject.Key; @@ -73,15 +74,23 @@ public class CommandLoggingHandler implements CommandCallListener, AutoCloseable logMode = loggingAnnotation.value(); } - Optional playerOpt = parameters.injectedValue(Key.of(Actor.class)); - Optional worldOpt = parameters.injectedValue(Key.of(World.class)); + Optional actorOpt = parameters.injectedValue(Key.of(Actor.class)); - if (!playerOpt.isPresent() || !worldOpt.isPresent()) { + if (!actorOpt.isPresent()) { return; } + Actor actor = actorOpt.get(); - Actor actor = playerOpt.get(); - World world = worldOpt.get(); + World world; + try { + Optional worldOpt = parameters.injectedValue(Key.of(World.class)); + if (!worldOpt.isPresent()) { + return; + } + world = worldOpt.get(); + } catch (CommandException ex) { + return; + } builder.append("WorldEdit: ").append(actor.getName()); builder.append(" (in \"").append(world.getName()).append("\")"); From e77393a51ef447ac69f21f52228a83aa8cb22e18 Mon Sep 17 00:00:00 2001 From: wizjany Date: Thu, 19 Sep 2019 21:11:23 -0400 Subject: [PATCH 336/366] Bundle required fabric api jars. --- worldedit-fabric/build.gradle.kts | 34 ++++++++++--------- .../src/main/resources/fabric.mod.json | 7 ++-- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index f8cb056eb..e6e3525ca 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -1,6 +1,5 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import net.fabricmc.loom.task.RemapJarTask -import kotlin.reflect.KClass buildscript { repositories { @@ -16,7 +15,7 @@ buildscript { } dependencies { - "classpath"("net.fabricmc:fabric-loom:0.2.3-SNAPSHOT") + "classpath"("net.fabricmc:fabric-loom:0.2.5-SNAPSHOT") "classpath"("org.spongepowered:mixin:0.7.11-SNAPSHOT") } } @@ -27,9 +26,8 @@ applyShadowConfiguration() apply(plugin = "fabric-loom") val minecraftVersion = "1.14.4" -val fabricVersion = "0.3.0+build.200" -val yarnMappings = "1.14.4+build.1" -val loaderVersion = "0.4.8+build.155" +val yarnMappings = "1.14.4+build.12" +val loaderVersion = "0.6.2+build.166" configurations.all { resolutionStrategy { @@ -45,7 +43,15 @@ dependencies { "mappings"("net.fabricmc:yarn:$yarnMappings") "modCompile"("net.fabricmc:fabric-loader:$loaderVersion") - "modCompile"("net.fabricmc.fabric-api:fabric-api:$fabricVersion") + listOf( + "net.fabricmc.fabric-api:fabric-api-base:0.1.0+2983bc0442", + "net.fabricmc.fabric-api:fabric-events-interaction-v0:0.1.1+591e97ae42", + "net.fabricmc.fabric-api:fabric-events-lifecycle-v0:0.1.1+591e97ae42", + "net.fabricmc.fabric-api:fabric-networking-v0:0.1.3+591e97ae42" + ).forEach { + "include"(it) + "modImplementation"(it) + } "testCompile"("org.mockito:mockito-core:1.9.0-rc1") } @@ -96,16 +102,12 @@ artifacts { add("archives", tasks.named("deobfJar")) } -// intellij has trouble detecting RemapJarTask as a subclass of Task -@Suppress("UNCHECKED_CAST") -val remapJarIntellijHack = RemapJarTask::class as KClass -tasks.register("remapShadowJar", remapJarIntellijHack) { - (this as RemapJarTask).run { - val shadowJar = tasks.getByName("shadowJar") - dependsOn(shadowJar) - setInput(shadowJar.archiveFile) - setOutput(shadowJar.archiveFile.get().asFile.absolutePath.replace(Regex("-dev\\.jar$"), ".jar")) - } +tasks.register("remapShadowJar") { + val shadowJar = tasks.getByName("shadowJar") + dependsOn(shadowJar) + input.set(shadowJar.archiveFile) + archiveFileName.set(shadowJar.archiveFileName.get().replace(Regex("-dev\\.jar$"), ".jar")) + addNestedDependencies.set(true) } tasks.named("assemble").configure { diff --git a/worldedit-fabric/src/main/resources/fabric.mod.json b/worldedit-fabric/src/main/resources/fabric.mod.json index ee3e7b612..705320db0 100644 --- a/worldedit-fabric/src/main/resources/fabric.mod.json +++ b/worldedit-fabric/src/main/resources/fabric.mod.json @@ -29,9 +29,12 @@ "depends": { "fabricloader": ">=0.4.0", - "fabric": "*" + "fabric-api-base": "*", + "fabric-events-lifecycle-v0": "*", + "fabric-events-interaction-v0": "*", + "fabric-networking-v0": "*" }, "mixins": [ "worldedit.mixins.json" ] -} \ No newline at end of file +} From 6162a47002e26c72c37c9dc7ebe9d7030f722bd1 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 21 Sep 2019 18:21:22 -0700 Subject: [PATCH 337/366] Force non-Locatable actors to use placeAtPos1 --- .../src/main/java/com/sk89q/worldedit/LocalSession.java | 8 ++++++++ .../java/com/sk89q/worldedit/session/SessionManager.java | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 0b85b6cd2..63e915ebe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -521,6 +521,14 @@ public class LocalSession { return selector.getPrimaryPosition(); } + public void setPlaceAtPos1(boolean placeAtPos1) { + this.placeAtPos1 = placeAtPos1; + } + + public boolean isPlaceAtPos1() { + return placeAtPos1; + } + /** * Toggle placement position. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index ef346d429..4e45becca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -34,6 +34,7 @@ import com.sk89q.worldedit.command.tool.SelectionWand; import com.sk89q.worldedit.command.tool.Tool; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent; +import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.session.storage.JsonFileSessionStore; import com.sk89q.worldedit.session.storage.SessionStore; @@ -199,6 +200,11 @@ public class SessionManager { && (owner.hasPermission("worldedit.inventory.unrestricted") || (config.useInventoryCreativeOverride && (!(owner instanceof Player) || ((Player) owner).getGameMode() == GameModes.CREATIVE))))); + // Force non-locatable actors to use placeAtPos1 + if (!(owner instanceof Locatable)) { + session.setPlaceAtPos1(true); + } + return session; } From 445b7706fcd3bef2972ac82378adaebb5a18d919 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 22 Sep 2019 13:42:26 -0700 Subject: [PATCH 338/366] Restructure how Loom is included in build env --- buildSrc/build.gradle.kts | 20 ++++++++++++++++++++ buildSrc/src/main/kotlin/Versions.kt | 11 +++++++++++ gradle.properties | 3 +++ worldedit-fabric/build.gradle.kts | 24 +++++------------------- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 101cff2aa..38b3e4ed8 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,3 +1,5 @@ +import java.util.Properties + plugins { `kotlin-dsl` kotlin("jvm") version embeddedKotlinVersion @@ -10,6 +12,14 @@ repositories { name = "Forge Maven" url = uri("https://files.minecraftforge.net/maven") } + maven { + name = "Fabric" + url = uri("https://maven.fabricmc.net/") + } + maven { + name = "sponge" + url = uri("https://repo.spongepowered.org/maven") + } } configurations.all { @@ -23,6 +33,14 @@ configurations.all { } } +val properties = Properties().also { props -> + project.projectDir.resolveSibling("gradle.properties").bufferedReader().use { + props.load(it) + } +} +val loomVersion: String = properties.getProperty("loom.version") +val mixinVersion: String = properties.getProperty("mixin.version") + dependencies { implementation(gradleApi()) implementation("gradle.plugin.net.minecrell:licenser:0.4.1") @@ -33,4 +51,6 @@ dependencies { implementation("org.jfrog.buildinfo:build-info-extractor-gradle:4.9.7") implementation("gradle.plugin.org.spongepowered:spongegradle:0.9.0") implementation("net.minecraftforge.gradle:ForgeGradle:3.0.141") + implementation("net.fabricmc:fabric-loom:$loomVersion") + implementation("net.fabricmc:sponge-mixin:$mixinVersion") } diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index b460f77eb..391029752 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,3 +1,5 @@ +import org.gradle.api.Project + object Versions { const val TEXT = "3.0.1" const val TEXT_EXTRAS = "3.0.2" @@ -6,3 +8,12 @@ object Versions { const val JUNIT = "5.5.0" const val MOCKITO = "3.0.0" } + +// Properties that need a project reference to resolve: +class ProjectVersions(project: Project) { + val loom = project.rootProject.property("loom.version") + val mixin = project.rootProject.property("mixin.version") +} + +val Project.versions + get() = ProjectVersions(this) diff --git a/gradle.properties b/gradle.properties index 4d41d3dcb..61c2c8bdf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,3 +2,6 @@ group=com.sk89q.worldedit version=7.1.0-SNAPSHOT org.gradle.jvmargs=-Xmx1G + +loom.version=0.2.5-20190906.190953-30 +mixin.version=0.7.11.38 diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index e6e3525ca..84d19a01e 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -1,25 +1,6 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import net.fabricmc.loom.task.RemapJarTask -buildscript { - repositories { - jcenter() - maven { - name = "Fabric" - url = uri("https://maven.fabricmc.net/") - } - maven { - name = "sponge" - url = uri("https://repo.spongepowered.org/maven") - } - } - - dependencies { - "classpath"("net.fabricmc:fabric-loom:0.2.5-SNAPSHOT") - "classpath"("org.spongepowered:mixin:0.7.11-SNAPSHOT") - } -} - applyPlatformAndCoreConfiguration() applyShadowConfiguration() @@ -53,6 +34,11 @@ dependencies { "modImplementation"(it) } + // Hook these up manually, because Fabric doesn't seem to quite do it properly. + "compileClasspath"("net.fabricmc:sponge-mixin:${project.versions.mixin}") + "annotationProcessor"("net.fabricmc:sponge-mixin:${project.versions.mixin}") + "annotationProcessor"("net.fabricmc:fabric-loom:${project.versions.loom}") + "testCompile"("org.mockito:mockito-core:1.9.0-rc1") } From bb8c150ed36004407f46541b27982333542638ca Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 22 Sep 2019 14:12:34 -0700 Subject: [PATCH 339/366] Update ForgeGradle + Gradle --- buildSrc/build.gradle.kts | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 101cff2aa..40fd86deb 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -32,5 +32,5 @@ dependencies { implementation("net.ltgt.apt-idea:net.ltgt.apt-idea.gradle.plugin:0.21") implementation("org.jfrog.buildinfo:build-info-extractor-gradle:4.9.7") implementation("gradle.plugin.org.spongepowered:spongegradle:0.9.0") - implementation("net.minecraftforge.gradle:ForgeGradle:3.0.141") + implementation("net.minecraftforge.gradle:ForgeGradle:3.0.143") } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 430dfabc5..ca9d62814 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-5.5.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 8e25e6c19..83f2acfdc 100755 --- a/gradlew +++ b/gradlew @@ -125,8 +125,8 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` From fa25ad22cda96470fe9d8073e59c50a48cb7f81f Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 23 Sep 2019 11:46:24 -0700 Subject: [PATCH 341/366] Harden JsonFileSessionStore against nulls/Gson oddities --- .../session/storage/JsonFileSessionStore.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/session/storage/JsonFileSessionStore.java b/worldedit-core/src/main/java/com/sk89q/worldedit/session/storage/JsonFileSessionStore.java index ad8e422bf..aa2d579fd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/session/storage/JsonFileSessionStore.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/session/storage/JsonFileSessionStore.java @@ -88,7 +88,15 @@ public class JsonFileSessionStore implements SessionStore { try (Closer closer = Closer.create()) { FileReader fr = closer.register(new FileReader(file)); BufferedReader br = closer.register(new BufferedReader(fr)); - return gson.fromJson(br, LocalSession.class); + LocalSession session = gson.fromJson(br, LocalSession.class); + if (session == null) { + log.warn("Loaded a null session from {}, creating new session", file); + if (!file.delete()) { + log.warn("Failed to delete corrupted session {}", file); + } + session = new LocalSession(); + } + return session; } catch (JsonParseException e) { throw new IOException(e); } catch (FileNotFoundException e) { @@ -98,6 +106,7 @@ public class JsonFileSessionStore implements SessionStore { @Override public void save(UUID id, LocalSession session) throws IOException { + checkNotNull(session); File finalFile = getPath(id); File tempFile = new File(finalFile.getParentFile(), finalFile.getName() + ".tmp"); @@ -115,6 +124,10 @@ public class JsonFileSessionStore implements SessionStore { } } + if (tempFile.length() == 0) { + throw new IllegalStateException("Gson wrote zero bytes"); + } + if (!tempFile.renameTo(finalFile)) { log.warn("Failed to rename temporary session file to " + finalFile.getPath()); } From 8af68fc884a8a32ba19b74d7e95efc5e74457894 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 4 Sep 2019 20:55:47 -0700 Subject: [PATCH 342/366] Initial watchdog setup. Bukkit needs adapters, everything needs testing. --- .../bukkit/BukkitServerInterface.java | 15 ++++ .../worldedit/bukkit/BukkitWatchdog.java | 38 ++++++++++ .../bukkit/adapter/BukkitImplAdapter.java | 13 ++++ .../java/com/sk89q/worldedit/EditSession.java | 14 ++++ .../extension/platform/Platform.java | 9 +++ .../extension/platform/Watchdog.java | 29 ++++++++ .../extent/world/WatchdogTickingExtent.java | 72 +++++++++++++++++++ .../worldedit/fabric/FabricPlatform.java | 11 +++ .../worldedit/fabric/FabricWatchdog.java | 19 +++++ .../fabric/mixin/MixinMinecraftServer.java | 20 ++++++ .../src/main/resources/worldedit.mixins.json | 3 +- worldedit-forge/build.gradle.kts | 2 + .../sk89q/worldedit/forge/ForgePlatform.java | 10 +++ .../sk89q/worldedit/forge/ForgeWatchdog.java | 38 ++++++++++ .../resources/META-INF/accesstransformer.cfg | 1 + 15 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWatchdog.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java create mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.java create mode 100644 worldedit-forge/src/main/resources/META-INF/accesstransformer.cfg diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index ccc025d8c..5bdffb5e9 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -28,6 +28,8 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.registry.Registries; import org.bukkit.Bukkit; @@ -52,6 +54,14 @@ public class BukkitServerInterface implements MultiUserPlatform { public WorldEditPlugin plugin; private CommandRegistration dynamicCommands; private boolean hookingEvents; + private final LazyReference watchdog = LazyReference.from(() -> { + if (plugin.getBukkitImplAdapter() != null) { + return plugin.getBukkitImplAdapter().supportsWatchdog() + ? new BukkitWatchdog(plugin.getBukkitImplAdapter()) + : null; + } + return null; + }); public BukkitServerInterface(WorldEditPlugin plugin, Server server) { this.plugin = plugin; @@ -103,6 +113,11 @@ public class BukkitServerInterface implements MultiUserPlatform { return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, task, delay, period); } + @Override + public Watchdog getWatchdog() { + return watchdog.getValue(); + } + @Override public List getWorlds() { List worlds = server.getWorlds(); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWatchdog.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWatchdog.java new file mode 100644 index 000000000..1e37852a6 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWatchdog.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.bukkit; + +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.extension.platform.Watchdog; + +class BukkitWatchdog implements Watchdog { + + private final BukkitImplAdapter adapter; + + BukkitWatchdog(BukkitImplAdapter adapter) { + this.adapter = adapter; + } + + @Override + public void tick() { + adapter.tickWatchdog(); + } + +} 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 f21d0917a..4bb915c56 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 @@ -62,6 +62,19 @@ public interface BukkitImplAdapter { @Nullable DataFixer getDataFixer(); + /** + * @return {@code true} if {@link #tickWatchdog()} is implemented + */ + default boolean supportsWatchdog() { + return false; + } + + /** + * Tick the server watchdog, if possible. + */ + default void tickWatchdog() { + } + /** * Get the block at the given location. * 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 e3bcac4b1..c940059bd 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -22,6 +22,8 @@ package com.sk89q.worldedit; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extension.platform.Capability; +import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.ChangeSetExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.MaskingExtent; @@ -38,6 +40,7 @@ import com.sk89q.worldedit.extent.world.BlockQuirkExtent; import com.sk89q.worldedit.extent.world.ChunkLoadingExtent; import com.sk89q.worldedit.extent.world.FastModeExtent; import com.sk89q.worldedit.extent.world.SurvivalModeExtent; +import com.sk89q.worldedit.extent.world.WatchdogTickingExtent; import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.RegionMaskingFilter; import com.sk89q.worldedit.function.biome.BiomeReplace; @@ -214,10 +217,16 @@ public class EditSession implements Extent, AutoCloseable { this.world = world; if (world != null) { + Watchdog watchdog = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getWatchdog(); Extent extent; // These extents are ALWAYS used extent = fastModeExtent = new FastModeExtent(world, false); + if (watchdog != null) { + // Reset watchdog before world placement + extent = new WatchdogTickingExtent(extent, watchdog); + } extent = survivalExtent = new SurvivalModeExtent(extent, world); extent = new BlockQuirkExtent(extent, world); extent = new ChunkLoadingExtent(extent, world); @@ -230,6 +239,11 @@ public class EditSession implements Extent, AutoCloseable { extent = reorderExtent = new MultiStageReorder(extent, false); extent = chunkBatchingExtent = new ChunkBatchingExtent(extent); extent = wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER); + if (watchdog != null) { + // reset before buffering extents, since they may buffer all changes + // before the world-placement reset can happen, and still cause halts + extent = new WatchdogTickingExtent(extent, watchdog); + } this.bypassHistory = new DataValidatorExtent(extent, world); // These extents can be skipped by calling smartSetBlock() diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index fcbd6ff29..d82ed52c1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -83,6 +83,15 @@ public interface Platform { */ int schedule(long delay, long period, Runnable task); + /** + * Get the watchdog service. + * + * @return the watchdog service, or {@code null} if none + */ + default @Nullable Watchdog getWatchdog() { + return null; + } + /** * Get a list of available or loaded worlds. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java new file mode 100644 index 000000000..1f822f90f --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Watchdog.java @@ -0,0 +1,29 @@ +/* + * 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.extension.platform; + +/** + * Interface to a {@link Platform}'s watchdog service. + */ +public interface Watchdog { + + void tick(); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java new file mode 100644 index 000000000..bb06fb29f --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java @@ -0,0 +1,72 @@ +/* + * 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.extent.world; + +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.block.BlockStateHolder; + +import javax.annotation.Nullable; + +/** + * Extent that ticks the watchdog before every world-affecting action. + */ +public class WatchdogTickingExtent extends AbstractDelegateExtent { + + private final Watchdog watchdog; + + /** + * Create a new instance. + * + * @param extent the extent + * @param watchdog the watchdog to reset + */ + public WatchdogTickingExtent(Extent extent, Watchdog watchdog) { + super(extent); + this.watchdog = watchdog; + } + + @Override + public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { + watchdog.tick(); + return super.setBlock(location, block); + } + + @Nullable + @Override + public Entity createEntity(Location location, BaseEntity entity) { + watchdog.tick(); + return super.createEntity(location, entity); + } + + @Override + public boolean setBiome(BlockVector2 position, BiomeType biome) { + watchdog.tick(); + return super.setBiome(position, biome); + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java index 69ea094b2..00c63f4e4 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java @@ -26,12 +26,14 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; +import com.sk89q.worldedit.fabric.mixin.MixinMinecraftServer; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; import net.minecraft.SharedConstants; import net.minecraft.server.MinecraftServer; import net.minecraft.server.PlayerManager; +import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; @@ -55,12 +57,15 @@ class FabricPlatform extends AbstractPlatform implements MultiUserPlatform { private final FabricWorldEdit mod; private final MinecraftServer server; private final FabricDataFixer dataFixer; + private final @Nullable FabricWatchdog watchdog; private boolean hookingEvents = false; FabricPlatform(FabricWorldEdit mod, MinecraftServer server) { this.mod = mod; this.server = server; this.dataFixer = new FabricDataFixer(getDataVersion()); + this.watchdog = server instanceof DedicatedServer + ? new FabricWatchdog((MixinMinecraftServer) (Object) server) : null; } boolean isHookingEvents() { @@ -97,6 +102,12 @@ class FabricPlatform extends AbstractPlatform implements MultiUserPlatform { return -1; } + @Override + @Nullable + public FabricWatchdog getWatchdog() { + return watchdog; + } + @Override public List getWorlds() { Iterable worlds = server.getWorlds(); diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java new file mode 100644 index 000000000..554e14b9d --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java @@ -0,0 +1,19 @@ +package com.sk89q.worldedit.fabric; + +import com.sk89q.worldedit.extension.platform.Watchdog; +import com.sk89q.worldedit.fabric.mixin.MixinMinecraftServer; +import net.minecraft.util.SystemUtil; + +class FabricWatchdog implements Watchdog { + + private final MixinMinecraftServer server; + + FabricWatchdog(MixinMinecraftServer server) { + this.server = server; + } + + @Override + public void tick() { + server.timeReference = SystemUtil.getMeasuringTimeMs(); + } +} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java new file mode 100644 index 000000000..597871cea --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java @@ -0,0 +1,20 @@ +package com.sk89q.worldedit.fabric.mixin; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ServerTask; +import net.minecraft.server.command.CommandOutput; +import net.minecraft.util.NonBlockingThreadExecutor; +import net.minecraft.util.snooper.SnooperListener; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(MinecraftServer.class) +public abstract class MixinMinecraftServer extends NonBlockingThreadExecutor implements SnooperListener, CommandOutput, AutoCloseable, Runnable { + + public MixinMinecraftServer(String string_1) { + super(string_1); + } + + @Shadow + public long timeReference; +} diff --git a/worldedit-fabric/src/main/resources/worldedit.mixins.json b/worldedit-fabric/src/main/resources/worldedit.mixins.json index 165bf44ce..ecd0ffd49 100644 --- a/worldedit-fabric/src/main/resources/worldedit.mixins.json +++ b/worldedit-fabric/src/main/resources/worldedit.mixins.json @@ -3,7 +3,8 @@ "package": "com.sk89q.worldedit.fabric.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ - "MixinServerPlayerEntity" + "MixinServerPlayerEntity", + "MixinMinecraftServer" ], "server": [ ], diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index e71c04295..b339aa62b 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -34,6 +34,8 @@ configure { "version" to "20190913-$mappingsMinecraftVersion" )) + accessTransformer(file("src/main/resources/META-INF/accesstransformer.cfg")) + runs { val runConfig = Action { properties(mapOf( diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java index 93fea255f..f7a82a344 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlatform.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.world.registry.Registries; import net.minecraft.command.Commands; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.management.PlayerList; import net.minecraft.util.ResourceLocation; import net.minecraft.util.SharedConstants; @@ -56,12 +57,15 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { private final ForgeWorldEdit mod; private final MinecraftServer server; private final ForgeDataFixer dataFixer; + private final @Nullable ForgeWatchdog watchdog; private boolean hookingEvents = false; ForgePlatform(ForgeWorldEdit mod) { this.mod = mod; this.server = ServerLifecycleHooks.getCurrentServer(); this.dataFixer = new ForgeDataFixer(getDataVersion()); + this.watchdog = server instanceof DedicatedServer + ? new ForgeWatchdog((DedicatedServer) server) : null; } boolean isHookingEvents() { @@ -98,6 +102,12 @@ class ForgePlatform extends AbstractPlatform implements MultiUserPlatform { return -1; } + @Override + @Nullable + public ForgeWatchdog getWatchdog() { + return watchdog; + } + @Override public List getWorlds() { Iterable worlds = server.getWorlds(); diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.java new file mode 100644 index 000000000..25f72c2c5 --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgeWatchdog.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.forge; + +import com.sk89q.worldedit.extension.platform.Watchdog; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.util.Util; + +class ForgeWatchdog implements Watchdog { + + private final DedicatedServer server; + + ForgeWatchdog(DedicatedServer server) { + this.server = server; + } + + @Override + public void tick() { + server.serverTime = Util.milliTime(); + } +} diff --git a/worldedit-forge/src/main/resources/META-INF/accesstransformer.cfg b/worldedit-forge/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 000000000..9c1530b89 --- /dev/null +++ b/worldedit-forge/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1 @@ +public net.minecraft.server.MinecraftServer field_211151_aa # serverTime \ No newline at end of file From 7e3fc6c8e75585fd8c439a876be7dbf5259fb614 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Wed, 4 Sep 2019 22:50:14 -0700 Subject: [PATCH 343/366] Disable watchdog ticking by default, //watchdog to turn on --- .../java/com/sk89q/worldedit/EditSession.java | 27 +++++++++++++++-- .../com/sk89q/worldedit/LocalSession.java | 10 +++++++ .../worldedit/command/GeneralCommands.java | 25 ++++++++++++++++ .../command/argument/EnumConverter.java | 3 ++ .../worldedit/command/util/HookMode.java | 24 +++++++++++++++ .../extent/world/WatchdogTickingExtent.java | 29 +++++++++++++++++-- .../worldedit/fabric/FabricPlatform.java | 5 ++-- .../worldedit/fabric/FabricWatchdog.java | 26 +++++++++++++++-- .../fabric/mixin/MixinMinecraftServer.java | 23 +++++++++++++-- 9 files changed, 160 insertions(+), 12 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/util/HookMode.java 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 c940059bd..f195ed7de 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -191,6 +191,7 @@ public class EditSession implements Extent, AutoCloseable { private final MultiStageReorder reorderExtent; private final MaskingExtent maskingExtent; private final BlockChangeLimiter changeLimiter; + private final List watchdogExtents = new ArrayList<>(2); private final Extent bypassReorderHistory; private final Extent bypassHistory; @@ -225,7 +226,9 @@ public class EditSession implements Extent, AutoCloseable { extent = fastModeExtent = new FastModeExtent(world, false); if (watchdog != null) { // Reset watchdog before world placement - extent = new WatchdogTickingExtent(extent, watchdog); + WatchdogTickingExtent watchdogExtent = new WatchdogTickingExtent(extent, watchdog); + extent = watchdogExtent; + watchdogExtents.add(watchdogExtent); } extent = survivalExtent = new SurvivalModeExtent(extent, world); extent = new BlockQuirkExtent(extent, world); @@ -242,7 +245,9 @@ public class EditSession implements Extent, AutoCloseable { if (watchdog != null) { // reset before buffering extents, since they may buffer all changes // before the world-placement reset can happen, and still cause halts - extent = new WatchdogTickingExtent(extent, watchdog); + WatchdogTickingExtent watchdogExtent = new WatchdogTickingExtent(extent, watchdog); + extent = watchdogExtent; + watchdogExtents.add(watchdogExtent); } this.bypassHistory = new DataValidatorExtent(extent, world); @@ -550,6 +555,24 @@ public class EditSession implements Extent, AutoCloseable { } } + /** + * Check if this session will tick the watchdog. + * + * @return {@code true} if any watchdog extent is enabled + */ + public boolean isTickingWatchdog() { + return watchdogExtents.stream().anyMatch(WatchdogTickingExtent::isEnabled); + } + + /** + * Set all watchdog extents to the given mode. + */ + public void setTickingWatchdog(boolean active) { + for (WatchdogTickingExtent extent : watchdogExtents) { + extent.setEnabled(active); + } + } + /** * Get the number of blocks changed, including repeated block changes. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 63e915ebe..9ac50111e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -102,6 +102,7 @@ public class LocalSession { private transient EditSession.ReorderMode reorderMode = EditSession.ReorderMode.MULTI_STAGE; private transient List> lastDistribution; private transient World worldOverride; + private transient boolean tickingWatchdog = false; // Saved properties private String lastScript; @@ -294,6 +295,14 @@ public class LocalSession { this.worldOverride = worldOverride; } + public boolean isTickingWatchdog() { + return tickingWatchdog; + } + + public void setTickingWatchdog(boolean tickingWatchdog) { + this.tickingWatchdog = tickingWatchdog; + } + /** * Get the default region selector. * @@ -951,6 +960,7 @@ public class LocalSession { if (editSession.getSurvivalExtent() != null) { editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); } + editSession.setTickingWatchdog(tickingWatchdog); return editSession; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java index 5fdf2087b..495b43663 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GeneralCommands.java @@ -26,10 +26,12 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; +import com.sk89q.worldedit.command.util.HookMode; import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.text.Component; @@ -198,6 +200,29 @@ public class GeneralCommands { } } + @Command( + name = "/watchdog", + desc = "Changes watchdog hook state.", + descFooter = "This is dependent on platform implementation. " + + "Not all platforms support watchdog hooks, or contain a watchdog." + ) + @CommandPermissions("worldedit.watchdog") + public void watchdog(Actor actor, LocalSession session, + @Arg(desc = "The mode to set the watchdog hook to", def = "") + HookMode hookMode) { + if (WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getWatchdog() == null) { + actor.printError("This platform has no watchdog hook."); + return; + } + boolean previousMode = session.isTickingWatchdog(); + if (hookMode != null && (hookMode == HookMode.ACTIVE) == previousMode) { + actor.printError("Watchdog hook already " + (previousMode ? "active" : "inactive") + "."); + return; + } + session.setTickingWatchdog(!previousMode); + actor.print("Watchdog hook now " + (previousMode ? "inactive" : "active") + "."); + } + @Command( name = "gmask", aliases = {"/gmask"}, diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java index 41f8bae07..d1268e466 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/EnumConverter.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.command.argument; import com.google.common.collect.ImmutableSet; import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.command.util.HookMode; import com.sk89q.worldedit.util.TreeGenerator; import org.enginehub.piston.CommandManager; import org.enginehub.piston.converter.ArgumentConverter; @@ -46,6 +47,8 @@ public final class EnumConverter { full(EditSession.ReorderMode.class, r -> ImmutableSet.of(r.getDisplayName()), null)); + commandManager.registerConverter(Key.of(HookMode.class), + basic(HookMode.class)); } private static > ArgumentConverter basic(Class enumClass) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/HookMode.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/HookMode.java new file mode 100644 index 000000000..113a45613 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/util/HookMode.java @@ -0,0 +1,24 @@ +/* + * 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.command.util; + +public enum HookMode { + ACTIVE, INACTIVE +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java index bb06fb29f..78ddc9db8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/world/WatchdogTickingExtent.java @@ -38,7 +38,12 @@ import javax.annotation.Nullable; */ public class WatchdogTickingExtent extends AbstractDelegateExtent { + // Number of operations we run per tick to the watchdog + private static final int OPS_PER_TICK = 100; + private final Watchdog watchdog; + private boolean enabled; + private int ops; /** * Create a new instance. @@ -51,22 +56,40 @@ public class WatchdogTickingExtent extends AbstractDelegateExtent { this.watchdog = watchdog; } + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + private void onOperation() { + if (enabled) { + ops++; + if (ops == OPS_PER_TICK) { + watchdog.tick(); + ops = 0; + } + } + } + @Override public > boolean setBlock(BlockVector3 location, T block) throws WorldEditException { - watchdog.tick(); + onOperation(); return super.setBlock(location, block); } @Nullable @Override public Entity createEntity(Location location, BaseEntity entity) { - watchdog.tick(); + onOperation(); return super.createEntity(location, entity); } @Override public boolean setBiome(BlockVector2 position, BiomeType biome) { - watchdog.tick(); + onOperation(); return super.setBiome(position, biome); } } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java index 00c63f4e4..f67fdcc59 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java @@ -34,6 +34,7 @@ import net.minecraft.SharedConstants; import net.minecraft.server.MinecraftServer; import net.minecraft.server.PlayerManager; import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.dedicated.MinecraftDedicatedServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.Identifier; @@ -64,8 +65,8 @@ class FabricPlatform extends AbstractPlatform implements MultiUserPlatform { this.mod = mod; this.server = server; this.dataFixer = new FabricDataFixer(getDataVersion()); - this.watchdog = server instanceof DedicatedServer - ? new FabricWatchdog((MixinMinecraftServer) (Object) server) : null; + this.watchdog = server instanceof MinecraftDedicatedServer + ? new FabricWatchdog((MinecraftDedicatedServer) server) : null; } boolean isHookingEvents() { diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java index 554e14b9d..b0f25c685 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java @@ -1,19 +1,39 @@ +/* + * 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.fabric; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.fabric.mixin.MixinMinecraftServer; +import net.minecraft.server.dedicated.MinecraftDedicatedServer; import net.minecraft.util.SystemUtil; class FabricWatchdog implements Watchdog { - private final MixinMinecraftServer server; + private final MinecraftDedicatedServer server; - FabricWatchdog(MixinMinecraftServer server) { + FabricWatchdog(MinecraftDedicatedServer server) { this.server = server; } @Override public void tick() { - server.timeReference = SystemUtil.getMeasuringTimeMs(); + ((MixinMinecraftServer) (Object) server).timeReference = SystemUtil.getMeasuringTimeMs(); } } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java index 597871cea..de54985b8 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java @@ -1,3 +1,22 @@ +/* + * 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.fabric.mixin; import net.minecraft.server.MinecraftServer; @@ -11,8 +30,8 @@ import org.spongepowered.asm.mixin.Shadow; @Mixin(MinecraftServer.class) public abstract class MixinMinecraftServer extends NonBlockingThreadExecutor implements SnooperListener, CommandOutput, AutoCloseable, Runnable { - public MixinMinecraftServer(String string_1) { - super(string_1); + public MixinMinecraftServer(String name) { + super(name); } @Shadow From da0ef12239a8afbb7c44f7b2b08a9da88c8c1baa Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 30 Sep 2019 16:47:24 -0400 Subject: [PATCH 344/366] Add Bukkit watchdog implementation. --- .../src/main/resources/worldedit-adapters.jar | Bin 857125 -> 433302 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index d1659adf24c493d50954aa4767a0ce884cf8a0fe..92171a9cc11fdbcb3d850afdd712ae88eca7ab13 100644 GIT binary patch delta 39914 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 delta 78224 zcmY&=Wn5HUAFWe#Bi-HIEdm0P0!m5=(k&%1(%ms2rKE_G!q8nqBOnM$Bhp<`cZlcS z_woT3XRm+mz1P_@zjI8jBQN+Qh@+_j0%JUQfQI&f^7Dau0uB>c%|1gtK|~ph11MEb z2&TRJ_Y*Vz&EF4@Kfs$`$e)Kv2>=p2(1ZWy;f9ff0uZ@1NsH72x$6 z6<#{UeNdjv_4`Dqay&`zf~LW>@5Apj zG~A)Q(pL1_ilo9V6znnrQo0sG~_#E~@00j#k2LUYJ`GdQo1N=a@JdQDT&pqVo`IuC0 zqzW4mMnQ+gnLr-Gtg!)Gw-Mp`IDk;h+fMERcL;8LGGZXxta3*#{tTpo8yGx??pvLmt8lr~xkb@yY1{oOflwpRxe@?yr(^0QT<-!Qlp+ z-$QIZ0Mk7|SP;N;Hz{xvQ9$-R1V{lK?pDe$dyMopvVUJuVNTY-N3aj#DCDqtFBEJT zXY;BALT4(HHdA9nuh@a+!8 zNCnQ`*S47s^uC8SSwMsPb<>j#48*+ir1lx8c;DExQsD1W`GZ&CN ztb7KD3zL!u(7+SMfpzz6^(i3!-8{PB)#1W;vmnZFB+>ldFY!DO^*%|u6(Bz9Z9fW_ zk^0W}1gs1XLT*wHuv7tZb3A(jVg#VwKrOq2Xc%-0pbX=+LcxVy%c7vbes2K?VcUwJ zqg%$mrKkni*7ko4=wlSTq%dQAxP>yv0eH&@pa^>no7wx1aZz=%o>f6O;M>vtsDf*l z>G6M~H+MK#TrC(MKA{O3h1^ow@r>eO63E+XvFS z>ww+gMl#s2`+w{~4HO(W?+C~aa#u&r1W5Hh$DJuq58B<;`UMbD5pE0pyb5Z$Pr+dw z)Nz->+??MuOgibmG~>5GX!o4V9ncf-ZK3*u2|Pg9UiyENH1C3f2iH0TVck`_UeJ#M zbI7`Lfdc#Bad*QehK-+q{@#UdJp~0~-nQjevA`$Tv(Nt@8F|BIgm;6%J@@G+pn-qi zx!(FbcM9{X{9iVF2n#%L-Y{ZCACm@gjy5B{A3oO?&%Nisl%sfGT3 zu9`#vnDFvYh&lkyMGLmMTi*Zh|0K}DoFgH(%lkgB%U&QSoSp$pa9@Qe3mBUzGnI_zmf8^+gVNI6q;0O2{2{%XEB-Y>p`gWC?WVQV|D& zl&jmx!61YH(C;8FB?Nh{zr8w01F5=;DJjSO3D#nEUom{10b+VLa9#?~yc49`YCo_* zkb-n;%*_r#3epWktd;fL3DRvENY0%g!HVsGIPiB|ked4}#Q7meRk|@L(^&SpQ>9xI z=O`337>@^#3{EJDq}&B?l7b+m={8o&BM4HOZegS{1Sw6o@T~>}DNVOfN(+LNrW@Ej zsPgAdnr;&|eGWlN(=Eqd7xLt80-kvSJYc)&_tnC<Q(<0= zI|x#APgD+tAP+saHg=Ja^m~XF2eG{?$mfUJFsxz(S?;a5i4*|ke?Cm?B|?x#_*?6_ z6bMp1ZeSj22iN~o514Zhga9U;hWzXWeGe(VXLDvj%I;&$eS{znLbpEF3nBQZckucv z-5f-w3Kyt$_vxm} z6wJ(iJBV3%5_vZ`$o=0SHJ<@H`iJyqH&P`u)4LVCHxIZ?3pyCn3IWQtDRS-IvjBB^Atx)~X&u>298XW)TCv zXUA*6R`ws?(|QIUcDryW%sQ~`e5&P8c+oC}j!8hw^p}0Rq?hlZ`+-sLk2UU{wbZ$Z z^Q@wcvLmRQjI%=z@ki>A_6fNByxzxMsnCigs?cSDexhu&9D&aL5IGdfF*sEy;{9&s z+i?d8*(CT&@$}DU#Gbg`wE0)wqGqAL)<>e`)SmO_tI1$+S{e3U3%u6IJTROphM%E=v4U&|NOBy?8^A$M{qd6-8A?Z^DxcAI7ODGO z^p`P*g<20Gw2Ma_ugG2`YNnRcn-M95Vy_4AZ3gU>pgxgUe-mCi=<|_~G~V zy8RCz(4Z@)h0ioo?MvIv$KSAAs$6KtQu03kWc>Uh^xK5!=dpUqP0Pw}DdY}p{R0R( zWn5)ddO6>eaox^dP-dJdNzT{~-?6%X1+HdtHw7zC7{4sPbRs*VQ;AvmGebIkIwe97 zF%b6`u0$JRGe93J#%UfQs%TjLEeIBs=8TCi8~1OU!2IVqg-KS%>Xf2 za~N{FY{dakp?>J5IujGSVkfi9OgwRTKv@)vq%J%HV0bt>eY^rtIUI}zfP`6~F(6bk z)5}@i%NlC7b0_M*ng5RbL}>mwx2E=6^^ebA9jd?9Oxu=xeZDaS9rAOkv1nJlxR~(X zX>Q2$IdeKGyD6+a%j|I*80O3l!uB|mk|rF)S!K4l%K z@mhtQg;&B-r2<{bix$maM7mI1BGF0EL}0@2a}~b5*JPCpo$5S6 zDYaRu8T5tf=WsPH>S){JZx#N;pY+lZBWF*M4plW9>)+lZN4q?3p_ zleW2|so5@^Lrt&G=qrKl-ioc9QOB4`KWxLb^Jo!@f>Ie})tta1!Y4ep6zb6o_Rh}0 zc8NkCTs+5G_`%sYga=P|uB^>6n@b3pv|7OabqLBn2=lEIpwPf;P@AIL?jx2V@H|+d zZvNE|J3n=mG4ao2I1Wd3?KIvqjrCHJ9DtS6)w|6LRt)1wiQzqrOUu>02)3gZ>U4aw3~MhCeKo>F;3*IJqKM=s zQ*)zzxUTA+;hqE`H*wki%1PlV2oX7b)f+cAOk5T*={7IBM@x9d;&>|H_K(NcJBY_= zf2GX#j3VmttNmWhsl@PMobRJO9_>b!S&>d?i(0M1z#zf(!a1t%Ub*=-EaD%pqAw%0 zU}sP0X%3wOo_tfN z1|p$QQZ<%8zdzV&#ab?wE+jQ9V>go0uFs|2s(0^#w=FoQKSGDT>BD#Y!c0b%1ItLd zqWAks`bzxqW3_?-=Oiv=YewwC77^%W2?p(2VnI9w%;Wv(p_!JwKbafp;`kTT#CqZt zDH6q-m=Fw&T&raJdUC1hyRn=i3opf>bMZZ7iH+?(`(A{zFidP^{{@S>sbJjBte>~-{0D>Fw~}r$BTZvJl|r=_npza^ zmgvas!1z3o%hyJzK+)0s?F?33`r6_9+$Y(67Q<%zaNf3qv{nyo4<(v0iJY~Aj7sh7 z?qzO949nJJSu*qK`m{dVLR*e8#VekfZYYIDQx@NxS>MYL-SbjT%r{})drfo zcPicRYsMiuDBG~mvbX-eubjUG6g7@vBPeShSZU$?k&dS?k;Dq2qH5GRZfx7zkL4{E z_1TQ+}-1xCSpY$9yz!;{Eph zcQ@R&tf+~o%@WtfQ+x8Am3BiBlg{T1YkBFIPiS7h=x}3-4}yiy4fEU>p;+ZJ*7ARR z%Z4co-qB(feSM-yboBzaeZ-(_SbJ`wVw6yCZFWjs=&bsR*z?@hv$cO%y#T}Em_TTy zn(Hd|`+TZ*Pxg!YK^kkPqi=8J3Md+C>_28SO#CL>2S071%GxT3$(j|0T6g@=r+7_O zZPvAkU4;&+vh|575?DSu4}^v`w#U!O_BtE{v;U?$vDKheIwG$lH_z36x%GRfQKHh> z;CqC7vEXzSNrv|l*B9C<%3ppv&&X>DTDAwLAy5R~Fy zJl!BE%QqvsidBcg%Bm$5c1Zua{wct!o56dH<%qGU$codEdsq}5Pxci$I?j*5hKLU0 z7qw3xpiGPupkp)C|6E6p6{+3Vt@-XSJ7sh!UP?%cHlJWr+E7xkRJ5zMUa6lSH;(!{ zsVm&R*v-?{uh1wYkcn(6k{dX;pudIvw)kzr@G5RywLg9IsI?Q1yCR3mM#J=sw`hh* zRE-ox!}`0HAhF7ii0gH3!cQllrEj`w>M^OK%PNs4$?r5z#D!Y}iRt3#Y}(uk>B{()t3w-OdvTwf zHFJv1p?;iIxfrKpHIZ=OGF!-7FqE1ez>N!XVQ1nhz}GH#@fhlLJYV$TOMp?O=UA*l z^A7{3nLl_gY0N2E{@+g$-(Z!r(Hx5Jr}z_pspe}_qZIzIVAxigO02>AcPf8P(sA8Z zWcldZG-Je?V0bi3UCAgfM-!kD#jryAthF>&&#A9NxX#de7O~dKyyWTWQM2Q$`n`X9 zeqBdhq}xGVUK^=@qB&zd!};`_ZH9;!JeJ=2)bus8zhw_C-NhXltDD9dy{4kSZXa{w zo_|Z*F$-}+&1}t*ea2KCv?T?YL)5>2uF_C}(ZaJ_$ObB|s+Y!6k)p*h^GJ-a@yF6_ z_$o&BelDEhiKv}s@}LHXc>#|*4n%}B*RbrAMqruSl_CZ@E4)wn5`b&IF#qrnUodwz3QmSd&%f+d;NTh)*&%7>94Hl z>UC=oqaI_?WxREKco4OTUA0eC7_m575u-qEsK*Hov@a_0@s4wt@QhL^^W-8f<#Yc} zzR_ILRoX!+jW((es{VWS+d=kad6v(P@Mk|6n0c znS`f&IE(mLfn#A{{B~YJXZq3Bb7~Hwr%se2g*CiH+z7wl4_GaH7;w=DwY1Y$HqgYI zVjQT8lA%QVlN-L23$=nTPNN?K6Ae^0?O!_NKOy#itI1l$Fvy(pU7sx7d59U>Dktlo zZl#!0ZIc(~#&RexAmAX%A%c1_lQ}Tx+)Ym@KXV6B%9bj86NufZba4V@ zhQyMkPXT9?WeTGXR-a|Ky&q>4qO9rCua55L{{CH2F(D;JSE`<^M#;UIGo-d*l2RK% z@>Laz<3WtSE_kRvtd<>7E}3H7%@hA`j4Y0lM_BBy@V^EiSGFyWlWz1TJV7Q1Rj-zk zg3~+dqM6Al1x~i_p)yMcH8sQLE}+f%AsmraL%JW9+Nix<9TiwaP5Vj$B$|YGi_&Lqy{vI+Jmz;sUmJ3lo&H+rTx>x3yjTi^#Gu|J0k2 zD*gT+Yjj|jI^U5*T*M3>apC!K@DkHkS#;s&5D|HACo_Rk%Wzx@etU#t-EgARKEB+s z!9L6WGdbz*lOAmEET)rw7S6ML-$++Il`EaAfkf2hu~gqD(ssS8oM&!lm?~F^6;EZM z+865eOgXTY%4N)bbh)ePM4qR8@hx@;*m8fUZ&zYV3fv`bPJjRTna_TW%@+jc8S0s$ zN;9*`YJU#rW}71CnbjGIoUtWBWH}@CqU0ijZmx29CU-nu*KmJlpC@|1 zxs`sIGuKB~{qd7}`%-7kbY+%UR}Q_<9A+2zV zo@9=}zQCE-<2}>kQZDfbrfLM{?{Ovv`%s!;2gvULh@G9`aYrUyO` z?faJev69tY*=KHC>u2A$P7A(}MIUkN$x}V}^VkATq0aUsm!<;O2~CxiVzbmfsBQxcFJy>gSh^&QR;Z_o+q9qhDDy)L1||U7_q1<5)3?xL3w3X>wAW zuEsy>k=Qg?<*QZ+*MxlSC!xokY1#7mr#fl9*YVXA)uo+y$d+b-dD~YOy zv{;Ih(hD~5{}ck4Kd)~ev$9r0WwR1lo+@)Ga|nMXma8`C%M&Jx6!fmzH(1x{Qu)`} zn2e_OO1dV#S6)!|oOY_i3H7Kr`pwkR8^>@*Wg2`!sG3hh(ctf9){!4w`hJ3AjDr&u zMUnGryWWyt+t3~7f=ksaiE%j;%S)=pXwVWKztJ4fkzS$6FP`GCjI{hb2GuOmXaB&u zDswz?C^F(YlBdYMgVCi9EJu((l{ny*bEqB{uFfLX4|-?WVK(FeAsdKIremzPt{z|8 z7qPFjBDJ+zH*@c7c{lmnvDj%%UMb6_xQdnHnU&!>rF&_?koIa)iHc{4!zZVMUnF|# zkKOTu8m6>hpH#Tq)9W)+HKBZ8jTUhn3r}AabBv362+b`F&8Z2zeAyV};AxQ)KU7UQ zG?B8-9_k_VSh;?L7y@)O-%n$tbx#WQiK$OrFowPUVX(IIea}gU=7UF5sF&24N}!kA z(;`c`FODY-h*aDSkfyGkS3~axK_i7t-H#&NpPAb(ge^Z+IHGd#ade^o{-`GqV>`$E zqt@_tdp}TmbUuw@>hTQ`;Dgz5+067LJWy#mu{O-?lOdOTMm^QSu3oZrMb!m*MMzA+ zwx-PAGVY=8!gLJZ$2Rx`k8sCcN}hQ;e8-iXuzkF((?B-;(x$K0MWC+YivPz1`E1*i{t4PZ*bv11RbgPsyXmv}j&RS*~(5Ya~)55x)I0rftJb1|P!=o1N#XRMdix@6l z7`T2e`*WnJK7YGv{Bpe~box~>>bP+q`pSlHY0+F|PL%@2ByK{A)|x@Hr2VJzf_gEZ zw9m(6pL?|8oPm7LkI2_qQr{*g?H1?Tyr~P}iQ6-ZbF*prm|Z@e1nsnV>(!?zQ$0Q$ zE+=^Ifc`VPiN&-Sv~Hs!m6xriSzOC2@cKdh#s)bHt*Y9B`o?dnFX^doWAjD;M{dD; zmw_2svE79OE3Fg=dyf&$GeU#QBZ>{I`+<(cHe1Ht5OxzzbIJzDEpn@0 zY>CMmyBO!;${4Ho(D$x?Oo#2`V>>_P{iSdYy9kiw4BgCkb`@XkA|Rdl`_b&xVx_x= zitan{E`9v3H9AMGR<*B)0C^l~{5E6pEqm;WEr4yAQ)(_TsYcTyApi$y>T5DnY zFp*kG+WsALqT&c)rT2REFab&F3W;Q01;8UP|AnxK4nCVptvrq}k80pRy?>xmsPWyA+?6k$GQDc8jOP{7kwm6FQXXpD`UdTML+Z*vm zYdxdVEwC|8y>Kg`YUGk&{QV0FkqW}NS}L8(1QoUesHWA0BFnzuUh7%!GFNgg3q=9^ z#}b=LGqj8-=SX4laX+SZI|ZXzx&dB^!%Cb9cK+dhgjK0Ff`37-C^KH>Uns`M!nuUN z;0~3be@e7mG~|;qJj-QkfB$0az5S`*HmEd-t*9p|DBGdeQrRS1`Qw8$9zEvSrewxy z?g!(uwQUK4%Yk{-wh!Yo9viE;>Pl-Gl^&XC6%^1GwJR2O>ypEWr$v0N$B zWlqaVa*NW@&`_qvaMiVyDH-y@>~z-#&qD_#0%wW$iFy3;u&SGW(+*KyL;n_gzvQoT z$q*TD&-hJg%xw2lHFo{j0!J=sY1TK=UC0-CV_9cfeZQ~Z-M)(T5M={ardP*!q)6e{ z64(p1HfoOSDK7lno${u{Am1saKVuy|?>Y8ALttO#;l2#t^33W$W#gz+cmn!hLKAvT z*5I~jla&OG;NF_yVxsi>OpC;)JWCn`ao6Nz+KZEz_U9#AxTMYutA}B;kZ=poO5wkd ze+3cG*S&);+8Gt!s{ea}gTAIL;(qpx^eIIHR9s@FNxXLTq$k2CLq>Cg`Y^MVKkd1f z5}NW^{kq*EY~QxvbHFtogx-*=M95B-+R2UI!8-Q-%F%#@p+D-r_6QwIBKi`}q-v-3wu- z575?%kM)J0Ybp~qCFa+54}QF(FD@N5tN-qAUE^fuKr^yATS!sj@Z8#z=X0D>n0Z5u zen?76%EZLj3yO8!hzu@j=^+ZkKR$<6yfInZ4$bV2>0hEaB)4gU5XxSCU-TwwUA?K= z8>h=q7qSUpKY zkNv%eQDa9l30)Xpbb_CNe`n?677kZAShg;WQXGt7CUr!h?!5WqJionpc=~lw zC5WL?&FF6rnUgueLrQKZJpZZ{BSGLjXp>EW1@zJ5?Fo|6!F0AlyT1atzVDJuE}MBq zp>NE1@oQf1N^}UIgf$#wMfp7nJrUO$EtObLkNkev7xU~IJ z=P<+ArmfR4=Q=HO@b{myk(vD!B>3r#o6GS11FbE)9_d%3hBHDHWiLZ(gO2S`oS?L= z-t{a@I0zY3^6_ut1SrTmEl021@g=+TS&!rzlw5Foq`Wts$q}gF{giwKr<<{=oY$tT z?UO9x<9==DP|c$m%7DUIj;(85$3PdAtG%${$^Tfg-jSFEYx_~cv-|y z7wdP$sT?h7UBZEGL}npBy_|gFY{n$F5+aQ_%T#MLK7y({G?*1h!lpn zl-^LLF8(ch9*xIm!$$aR{NtS1hTKGq(QoS(;e+fU8V7}wVnT+P{Km>*%pXuCQ-hgn zB_d@WZnoj5Mvv8&vR5Tn;hi@0J9C7Sjhtqe6Kub;Cf+Q5|D9^@-R_+c{>{z6y^RcZ zT5rZOW3Wu|0I})pHqe|!MU;|8K17ctGb4VLN9a$ zz3it$@oV@P7n`3!bHt$-y+{xgX-f9bPI`zYEa~#l%9mM8cs*@?{x=89<<;x!gRb9^_Ok(o&D)rVq*Pp8l5EP`QwV5z?W&Nv0 z=lnWBV>#jdcw5bJ=n1R&@|(_VtRqzOCtv4U3ZnQ&O*)h2AC%+LPL(-BgOawg!-W3^ z2ON{1ZwO9nQ@`E(cJ-BL`}p`tnZwH=ak~QOy8}X@(0>e;E;gf?&Zq49GHD^tMRD;; zWFJdIEl?hvSn8GRxa(=0bQJrE3BPM4TwBBEeXurbJdUlW^AH6er4DzzBR(Og4mXLgVz#Dqxv=LO7LhF8)eX$ag2S5`4oM*{gn%0ber%m)e|GqKx4_2 z@?W{$bj|M)P-=8ZrvjuiwEs@}u62%Ou8}0flXb_hHEB+%PV+j@JUp`8c5_L>ZhL?t zBqYZh{1VKMfB528YV^w3x$7E}`B^`xJQHEY?a)Jo&@=uOw^Bw31wx;i)(s|*_Ty{x z2vC|{)4ms2Gp-|fiuNm-H+efKU5Zzw)j#c}E@f!mda=KHI(zQ^C=>Stw%dlvaT}kT z00zHf@TMQHlZXY8#b(f}6KlU$s!#0FoCr{$OhIQ9s=@FN;92JC>xORo0I8z945R6Y zIr@Po?O2k8!}N_k&{jc7ieWkyK78hdIxp%4?}u0&2YWN|0VJaT9N;gNsw$Iv0!4d2 zU^n)*MqxL0wyIz^M(4kGBYiCAnAMEi_ddLJ|B|;QcDsk`Lw{gh zWNFXvAZ;Q^s%1TY4|x%Z1!+;3*|YQo{%+z=fziC2-2JYWd{Bl;%y3L1%ffzNatv!z zOZ`}mBGk`#$Ff4tt&ZE#2j6OnaH7j$i_pAdcxz_kCc?>4WhBOJM>AeOKo27dt-sWy z30?6qS{^1hUpL0>So_EGJ^2Lv0Gh<}4>vjx*Oby1Eop%v4V#8=>pF=26l}YoEs8H4 z#C%F=Fi&gGL=4RgKwHgwr}C^lCat*38IrC{sCW9Zk-)XLCuSVOoX;dTw~nZ+y(D5n zZr-*LrHpBGxr4}yDnj=A1*Vd64d`UO>5*qcm^)az^fElJx6q8Q;vv_^e z`0&2Um-@#b%%7aw0fhR=97U8;jLJzU}=0tC}J?Gs7_6hasN5&UG7XvPU@5h&dg3 zBIic>BNf{nTk63exsR?ehgLSn&I3+1S8VK#`pfcf_Gxx{SISM!t^y^~|9I^`tZE;+ zy*~W;H7BOGio=P!|)MbvF+`fHfBm}SxHLnj*5KMrFmvbT+bzWv?csq zM)iPI7xua~h6Q)dU=bJb#<;Fsy3|(L%mBHHhdoQG^+WA-q7-pm-nD6^?s}m`^DYKi zCV{}ej8HeTmIM&2O>|2ov{j8)$0y#1KZO75Vn=Uy>bhpK;*~4ac6Wm*Yl(*ZRCoip zU+>dCQ4QH#rsF3vg(-rErQ~TY=T_`B89vqGwR{jg7RwY*$v@)_%|deljSdAkA&hr5 zcc%rH9JfeJrK^;~B!ms#ng1KipQHRYxOCh!Qe(wqUzh{)FZ%9;c{%-x+ktWq%^827 zvkS_L%3(_VqTTmPU`R6M3oTpHe)CjQk?p)@Rc~U8q2vo(g(hm>&e-1u+&?qVlMf%E zKE^$xX4U4N044v}4#cdJ|GDNb`jzulJx3lY@B(i$0B^>DM9lm1OrQHqZGawn{MB{4?L%d3)tY z!^JaxVoLF*@(?ltsgE=7=t2bR%$N8TV-2^LirK@*W&!XVL>Se8}X4Zy8kP`dE2(?c@}d-idXf zTShCC72!j?5&UDQ&=t@UxPx$7~X;zy_ zbKFK`Nmd#S!prU3aTa!e5X<9g2^FX7pTeBm3gAE(AciRI++CCnH`F7$P*C$qJZOBA zo^}?Oyrk?e`#4v9*bwVKIkpqZyXnfN+ihIShb1D!hs)CCR`%XkdcLl+=^)%^j``!u z2YI{nteq+!f*V(!<)3B z_t-Ot1F8gbu=_ONf0Yu`1p^kptNV5+f3Oc(1h1<-O?^l<>~X=NOec5H3?7&L6to$> zdPO1Tm<3K?oaNtj;OGBv;do&ce@2Eb?LQH4>Uj~y#q0t=mx=nU?hS56O>X;TWMy@> zXYWRDXB9d}9y(Kt`@7xQhjg2DR?b}VeYG%_%-;Z-#83QFhLxW* z&(*j-OXz>oXx)Cv`;lbZ*2D6+H4g98L&QqsJ?MJv+dw32W zs-BtxDRp)FD0ZBb@qlzzAj%vyY~4#r@d9?V_)cLV1v}7mbUq@_0FLV&tE2ET#y=fNPS|xFnoAgv>;a-9XKogOEJ4evE(I7 z0R~BuxJ=|ueB~vlR&FCyTI)SI7gvyEkqJeCri8l%tyFlSNYQ-5sfJdcy?r}0K^d*R zhF~u5jWR*@t6jfH{HHx2WBKW(D>bHuEwUa3)sQbdKNXCg*nQwU_WJBF?yRRHVtJsLn zb7Fm}_6YfPl}Y^~bHu#9vZVbI=B6&Q%E&5e>}Xi115@sMQ%6Rfb*7BIp^4g)059bp z#JT-ZeEL<|^N)B?H}q*e&2LN@r&-Jv+NyI)((E|>)v`~2LL5)sU-Fe5nS86m3q?Mn zObzP%M%mZ)xQ@iu4BihoFiTb%co(PlWqM;hA};F+i_e zU-C4zC!D~~=RM!}R8#nyn6#H%%g7TKK{#HEVGvcTU(wnCE&^^Re!T@q@r-B;ztnA;bT8H7mGrG79O1X$|)+E2DE8Qt6#go?77yCHCCUn~tZh8dT@2P0r4u zk6lRF&Ikw3oQ`wtx1UVJkd4y_kYSL6Ap#v~6EQ!H?AD>vl%+x)*6vGqp)boZLyycI z4-TmfUdW34ahWu0pe-UfKwsXKaxr!mjV)gSIMsJI(xR(;P_}C+qwMiy5CgTgjE%|A z63!Kbbjq+voROq=oNKC==8<26N_rt*+O7jLGFx9?pw%SEW-1qYiTOVs+SRTNir#hP zkEJ#U-(-Pyof0w8mc@U*h&epW0WP?;iRbewjznr(ELxk*ze$Lxf?Sswx;jUcmn&nn z9nq7_bZKHmN=nKtD~>hVlCopTZlJP;jS6xreSYzvTJSy9yxymWV(s)KwryT~^2_T& zCW0>A8C{y>QO}A#DMmK_?KM*;mxP2``a_ncI3j(a`(Zh4n;LW_tyflcbfIxPtfaE7 zXTzAHYvUG`L_?1!MftyGPb+4ZhSI!E`FGXeR5fFr%D|S*lxbaOiS!>6kIg9El;UJAV25lB(2C zBw8`pMN35ePw0tzhtIEFf6}607h4f(1UAjz(4@MBAYS577Xy(mtD$j6U>cW>9y8AM z?lq{a?=Qz^m98FICA#&OE&`@gE^B z%yqpoe8twh%xQ?`4z#5&yhGdFd9`$kB5A+k3A@G2B}3B!QnL4OG}yr$ zioK0D=vAW^HHW{kEAGNS%kpCh`P$nyK1H5~4o+B9@i$`KWnuM^en>!1{2v-+4_H8l zDYql71c7Mc;uR@hj1l5;nJzS(ek<5GTKppkVitpnrPGjsocrgOtT-x2hd@g(`Y|xz z0%t`q593J;`E$)yoQSPrJrUJ^$>dLnpqcjJ1PNCAD$iJO)0P^a^G6*oxk%MM_&B_Q z`}EnX27YEbQNnk$1Cfte-DsB;=z{l7{c6j3GS3(1mlYNUh!w@0g++JF3r`kv(*ik} zt69GnOAv*=3i--opk2PdC$0S@qQ9eX<2U{Y(=6Y|O#R&_DR_!Y1obqsl#&4%2bGG* z2V+rldIyM|N^GkwKB_c*@h>x`+xnNDH4zRHJhs`3_Id%E#ovj9u78(R9_nYaj0(EO z{eN%q-#lDBOcf||^Bn(USk@yHbogO2K=%GcX0bK^F~{u-lz1(N5AHa=#z@XI2?)u# zc_kH2Lk{BRynUhIclbxwTMj(I6a4i4-LpAwu!P|4I~v9>SJiHYT{!10Jwb5JhFZ?U zgp04t-K1lvyF|VuOGbj`s!8NYS#E!RWz~7|3z)P(r6I89IS3Pec`=Mui^9z4s~(HoSKHCcW9jzWpIrUB1wxg+ zHqUt>K3p2sE}o@2*9oMHf0gb0MALidTxBm9-e*Y2K9M10kQ~%x@&5Q(!KDR)NsM-l zF4P;!7{QbHFBH%F-6i_wp~@oY^=v=SA^w8%C0BbHGyhY5{uB(vU!86xc5N~ivWz}3 zVi|dO2&a#INQ~b`@S@^L=11%)TK{OS%I-Twdczck#u{;?eU+;T|(`TltLg9lQu zia3BU%ybR{hH}5MH*<6A^1XS2p6D;~33?c;QIZx6#6pwT$I?g32uG*I3zt{^5X|*q zF&>LIexNfQJ*vUI&2Mhx#aD{2)yN0vd7oFj_-0%E!fwl)Wb5V`b&Tx{lI*N38x^__+xwD8g z_Y-(V`KVTK==x4Roa-k%iQI8p@iRIDsr(vF!PV2`^e|kMtq9AZ?jyvFQruV2@s)`4 z_b@Oon}YVh6uHtE>pA!2_R^TBNi=rHt{y+yOJ?%t%>L64(3b4@n!VDW=e@|XD5fIG zV_e>;(G~S;jY;J~wb4E@$BQZ=b&?AQ8)Fp`V`y5-!4L=bBA-! zXAf2TB4G#l{5V(h1tO4q&r0P&;bP(;wCaQU#cwEqQ(p=u}Ju2S-aUcl}DPygg2PS`!wiH!Xq!`?ty!-10aFc6oh z2{H5!Le`bnB=VF$m`Co6Kbj}oSIj837Z!#{ICD*=9E6!`Q)lB^^)jf6G1CkszTy&7 zk6leLoei9ap_mpckIK!|YktrdD{9FsA1H4WipirrPDH z>KzTy?PuRM9E7D8W?CYC?(1Qe!rV^zC!vW4;Ym8W9Wu|eGkHjsJN(5GSB?6Kdhpj) z9ygEgt#~zOw!#z`A680h2={iW1~6S5P=wH~xT=)KbEwtz1@1&)x>^$cUa`HB<@ZQH zzLOxqXOhjR_6o(gX<^z%qf)3 zwC@8X&NbusF>n4{AkAJ}JX;4b<$RA)=_c(&ydkI8i(f-JbGCgB#1}e_!%0O5WLcq1 z!;E`*{f54Dd*|tr{fSonZmQm;kTQhR`+dnoZ|`P^69SXd`=i%rvczeR0&ycZ&mWd9 z4Vd1(mN%IRx5x@nYNM8M*RR_5IZ*D!7n9B>~5iHv=9%qxx^{*~XvzVthME8LjUNpqIFbNxvt zeLGcxzj|b#rik+uQ0gx(8o?E6Or~PAibFc&lO1gsXUKC=;pR79-R){#4d}MO3i7YY zkyM#)2j)edCwZzOn6r`xG1@l>myfGIF)4tR{Fj7SNBtl&e$>Ac~sBdvq5bZz%S+q&g$8q zmVG9Mdfd=gW+4|}+2(jxpgWwIj8LZqi!)U1tI=eqKS7GkmJ81;s8(`R&#W-x%-GJO zAVDi8h(~={7l$ILi!BE$4l2zI*KOKYMQn2`#m!a`J}c*v2Y!-c(7jBWC9$iSM4Db) z?>>$Fhu5zVam!HeZjA#*nVMymeeLX7E6LGSZ}XgkhbFmzEH>XZs9einFVqGRgyF^A z!t{&C;3+FY`waB4G&y7p4Qh$U%pQgX=T}R~DA`xFT*-@5eXyx{#t7^ae%@jwz=bP@t=)>JDIp*#-xKka>WR8`CSJ|TycE(z)G1{I`{?vO5# zE&&mQBPk&r8|f601_eYAK~hCTx&;IzloSyVfBT%H#Qpg1cdg$a=dN|vJ$K$`o_S~X z?0Mfkdo~Y|r*R0i=$i|DI5&ns-U?HccxG<_vn`Qql}R$dmv)G~}AT<#~D2M7(&Z7A6>bthtT5$dT| zg%Q$LMJT#`u{T-5<=L)qDoSiqXti@&#c}KIYnhTI8~eg$Op_!+9`hA?biVZ(8hU78 z43XRRqMzFfh_dHBOP(52OcbXagI&J1#!9Pt zhYw?a7*aF6u<0tDHd@aR0lk>OjHg;lCn(zM8=1{h5bu$$thFD`qbZcrFo%Ebl75Oq z8D&tSSET?k;|PBYiV^rB)2H^DF|&7SGM>I_jR!vkzVC{D_Y>vS>0( zaG=b-1VL+!Fnr6@h843|r{dOBRg+inEF}ymSE&`{z!!a%XGyJV=>k>mE4fiHC!fg8 z#&gJ1mgj(FZ$G9)2@KuCLQf)PV)f)|F)zBNgC%J!Hug?@+%WZR9y1{PfRA*e?!D7_ zQ8(5Bl1+j894T9ee;@?6~ZIrqv$3Kz&ef^#D$KJ*WHGg%JPjcFSn%6?URtGX9~^>bx5c{ANHv;@CkXIPKP;jw$B6ITErk*b9Fz;(t%tdL9Ex! znqXR&$YIi`@*koDxi+;y>MQFmZf;ZGIE!-5w>^9K&NbMc#_FbEi!#)pIHRaXxSG_T z#pIB5WMSXF=KQp1x`pctr)z>->Sj?fB6Yqdm+v|c5f9&A=%n^EtCtC6d770Xg)vjz zn8qScU6XD}KUc&c_i(`ViXokfV9JJ{c(Hx56FEoYTCRd1ui}+X6 z3Q@YedHr2SC9))nNOhkTnrU%W(L#T`g*<#m*#=TXB{)La_d6%1IyTpH!fZskvqJLo z#2kT7s04qmu&Y_kQf_>>TJgN78jgNuag(q4J*}kRc#;J+!5}aD=PskgUGvkk&FBnq zl_g}z2`qaP=hgQjvw33Mpw$v9uDI~1zL3w+qmQC&$QX0W5sKF<)wByuBw@*$0*Kk;zq zC8e5!N>%M&!u<|?lcjN&lp)HoGU7j=xw=%`AN#=X1qh>Gzm&%1ThQ_gaaXy-;z@qz zqh?Jn_1G8s=fP^K{KC*@`&xOVPIon4KmhZh$-Hj$`djV~&2{`^dql0w+Rt;^kQg_e zv--@i__~{0r4Lp8plUd*F``nPkG<$g>eZ^ST#U%FNJyb&;C?H%-mr8QUR(!nfx5;@ z?PF#V-en$hKK9Q)ZLShV3H1qzeIWNS$uJ4{HgK=1rMw`8$=LBZ^orUOUm2W4jk=Gw zFRYOL+=*%IY9hU55~*(xdj0pn7OVPb3j-nEPvbNT>;PwcNcv@2hJ5{nV3(JR_!lp~ z{A^SXTza7!oK)^?cR{r-LipjfkfX4-)PxAWn^SYIEt%j=`>FY($@tp`HSw{(;(DGA zlTFIXiCZbW)9tD;Pl|vNZ@MrYNJ!xJWS1&cdNgj-$aYhFvoCtDbR($QJb2R)OVwLU zu+lJX#a)-y>WRQ3ZjpsMkD3%(BpV0xY}D`6bKHLDNTV)F?EK*leWW6Jw9dO!(y5QE z?|X=cF1Z=`kF4d!$1v5Z2@N^Or_Dg(EfajRK21!!NEG#VG0Rw7fu?*gfR1%)xtC@* zrny>#797l#&5hQwQ6^ooPS2)MiW6ISOIq9Bz3AKhbF6%6xvU8D`(!=$6aQty$rCb_hLkwFvdrPDX@u-GYl&217R#oMQD><%-p;pQ){EU;d!?lCPCtm9Blht3o|SM0FAo`OU<)pC7zj zx{{P&b6L*lfjj2vbIz+i#BFtI^UuxsGZyUe_uIz!MsFIwxCT*ywvAG*VTl|#{%SH1 zZAx?7ZI71@h5628Bf{_Nc4+h81OP26U$jkIqK5i01in>M{y+-#O)W(?GL4EG%7j$XdKxk0l(UTheXXy^5*B$F(CVYo#xJ#dDuwe)cRoA5# zERH*7i%)e%Z&(vQIR}kS#cZSf`n8p?h~1cP%FrKIHjjR6>@eK2(08l7XMk1XawcoB zK5mqx6f7@N=*lP9XaSGmE_=@{Eg#X2$FdoS(DdxI|AmU0cP zXy?gb6LtMK{>u|uVdxf~S;G8eVIz&spOr<^9IMMyAG`7Q0O?Pl{RVFbJ$1`J9jNHW zJRRa3vMn8Qj49X9V|%z_Yf`RXoaPu&-t=VBU{z1ZqozpuXIj{*`mzhgiGLn@T^;c4zP;corXYMqr5DWGe65(;>4x zNt3DaZ`DJ**)dfw@de7e>-h|;e-WkNrcaV0DtzZkhH8}XW#cUDS4ixWg z*$BMVd+q%F=_P4~XlQx1c3-;V)AGQ!ZGR2PIDYn+(%K1%nJpi4rvfvXV3bswi45dJ}|?cAx>?F+^S$J0-TOz!?9 zu{bI_vMz1eT5wxgf8^I?@LO+vd`0s6%krb5BePs7O3TLtxPwsV?+N>rB~o=mY%98< zc~ckoD_{4y#S$t)hx~eY>PeM?J63-MrOvfe=?jF_FgxUw^tpV;U?_a4hpCQ!O`$f{ zlaRBPjMVc>xfCDvY%=#wt4pRWHGL+iT5laDS9t82aj!6k)`GMsor;HQMtS zpxr{0Hi7V7dAiep`KywH8XLEU-hxqeLR4Z5$ zlyVGF0>h%67v^2&uZ0lTB{~~^P_sdcGjpWAp(qhjS``ziSmdH6$eQ7Z2dFWWva6`s za9*H_&3N+rzCL@pMJku(BY|GgSiwh0qEt!~op|$<1CMKBppG>rooe6hI_*{Y*aY@# z1wCsf+@ZF*Hoy$Rzb!a@*Of5^~mriHebKCDz1& ze@x8KpfWUVsyRVx0U6Wmei3m(CzBBK8bIy^>R<=e zG>)hHIX4zr?Rrt$5wB?d%m+8fN_7YT&MBrrqZr7jZP_Bjh^_LPLhGw=^9b6?kM5en z8rBVL6LX}qF&#lAxQ>siheb669`9C#^11pDm(9r=*i%DSA1r3i%~jMEhNk)XPTdc8 z?GfF^+uCv=*wA~zHYYSJ^z{7otp*RK=TX^LhCweBU-xZ@-rxw+82qS<1HMl4sO9Vv z#55wbU*<5z^{S9X?LV~q)O~GpQQF;UQ*ock?rFkxZXeN&_#aLzT&_<&hCf=Jb7r!C zn$cNOMtj&EFQ(Mza zMn7df1^_F>}S+ShJ#y#q|rk41MFcP zJTf?9=&e}Ml5U!_=eimmOujOl1Y-DkqO-Sm`Yx?p9pT8c|ICHo{T5n4EaZkI>Lctn zX!1RYRjSb+{pMHB5(S9Yn!U)^`$Zmaf=VXSd96w&EtMV$_H~>KYy?)!NK>2 z@KInGg)WD)+fM&Fk@6k-4mSoy_ryK2A8N!q_^%3Co67Yo8518Tt6kf+F1SbSi{5&# zWo%+)?GCkRqL15Q)%5$<;+I{l`$z`Xq%;Gm$LFEky`$6bAAfnxvDrR?vsc#%O>SW0 z6ZD>^NHqzV?tO0}#6@FDcRkPI@%7GyPBQYQo2HRf9HriOZeMoht9)M@sNnpCf{6K+ z!_8NG*j!GR(W>jqZSW51EC%^p>5$U zJ9vYc@5_3>Se?=-B(Jv%^H&f{t7U1eNlwGcA*CVojKuwYQ=kJe91k$nzMR3{S^ssuscS-jW`DF};+A zYIm1Uzx`QRN%|2P?pvOPYwdYG0ayC-H9Nza4|(@Kzx4UK>QEWDX_ol@;`6A)wQ0^y zb8@=~5ojV6Q<`ws-3k2p8`sTJ z$Tc{EwpE3`Zu;4H4}M-1+cZ{9j9hyO%l)+spEp<%tsjC70x=?2h4^B4ybXDJWZs!P zZCDI_=l{+|((6^noORdxG3LT@K7T=>7FU&5qI-u>eZJxPIK~tPa`h}00b6uTw_AeM zS8l{V^{1U1^z`9Ny*b#M+&ng3+lW~ON!^)Lxy-@TaPcP2sPP~(?c|egSAsCb2+a?6 zz`5s(vhT}H-n_UzJ}yzYk-QT~sBuo&?>;d2eVS1{xkRpjg|r$IohR@|Ly@|N%JyQo zWhlY*OVHWc3^hEB^Xk?IJ6qN?#wk0K$vaKscg(+BY<}Zxu1jEXUCsS{>tdq3I(td! z+d)Ym9IpH0!_`by1*`1xiUk>dG^OBIAbOWNJ2l+DUprhe&Ww124J1x;E;BWyyz7?A zvZu*@lQ~G@BlmGcT);Q((y#XdckGr8_mgZ!_dMI7bBPZ&_Qk95a97jEY$P74*?#(l z)0X?RNU^sK!?|AQ>(m+<|E!n#O#2tExMbxco!IOprQpph2$r{`&xays;q?LK_hqJf zItRhmsw&FMncBEqc!${RRu`<9FUIGSm66;z;(z$0YWg?3s_&BE#G~g{%{YY_Zko^D zUO2B1wGU07O-m5}?X=+fk-qdGlyIUse6-@1HjCtL*rV)L+xp}t$afKwMp9*6mhrMT z{0Dp90au-JM%gpJ2EGqYBQPSyaot=^{{8rYD|3tTtBd>@0t06dT^j%A+17;(gbWcW`cGETq56cey6a%gwYYbKP+v zxbudW3BTdYBA@w~bU-R!|B^LF_YiJU$!uXQhU5sH#S7X*9a@ut8<%VQsa-!D9O+BX z=ulA4LxbG#dos;MuI_T3TQ6br7}Kb5$Dg0O^nSDAk?<4d-fvSREvdg=l`I?DDEa%B zT9le+Cppk|ea^@fHH;S1P)%I0AZjku?P_lQx{bQ)JojkQXm^%-#O@&*@FQ0BO^||^ zLRyBwm3@?g#t|FyX76sV(DJSL_foWI4)vtFA8DXghYU<#sZ?wjr=>&f=N*ii>g+ZX zA3ejRN*w|h7FGNkE-q8S3ft7*vD545EBQF)K629Pyt^GJEKxrci!XYoe&vnv{T$WN z_g`#+651yoO(y=_UK$zJFtVZ=DXbXzxp&XVS~Ectn);-A>V-(vJ*Uo@JtW&6C|I1Qcgn0UVj(B;t^M`xtszYelOS#Qaz(Xvaj_lcSPr@rc)Bh^ zc!_C+d(_HwqWlgw-f{`0_x>lc4D@OGMC$@Gu34jHZHLtDkn;EWwe^x~O%JYgdXOj7+G0b87ae(^{rTP3!WTEbc3HPyKDz zNgi~4d+*edxoCN?+p$WL`sl#dVJ4t3q~rd+-woY4`$Q=W>e%?F&lnzDdsw9VhIaW8 zz*Q+nX_n~F>u%3Sc&)z1LQswN@~)lW^EXAx@gvi>7-jC?E%>NTKmAbx>oN4pwRJ+C zfd*dISJ3YoYct(%H>7SlT(7$=PptbkS9+OduARGC|4`gB+y$kloFnbFhImpIemnCm zo$%RIuT|~xmdznRtFB^wosM<)JlhZZXSFwz44(-0DvJ#=rPw*7FD;KSdcP$ftnHOZ zPFf&&>o=0SY8m&gro@JMv5ts{ajeXxvo7kAhc7;K=|dBXgCc8Ej<`g5d7#`w+&Qfvb4Q!|dDN!icINEsKZ!crKkj#Yk>gV;|59h^Z9j;Qp;9ol8Xol- z*t{SX4fW7zj~-^G{(ftfYM3{3fNJW`RB zS4nR=$~|{ue#~ShMC>Iu>2Tq^vvUvMjjyv!YEzkVdjXfcX4q6Kf3TW9%u+BL?O*K0 zk}~1_9yp#O@P?^!WX-j(k&`+j)$j9F6PnteQP=yR>!^e?)WFCfx4rXc1-yEy+1bj? zrfyyy8Szb=EBYXtO72%OxrJ0Ocv#AZT;8J1vPgk z)_N&uyMH${dZALbPtMx)dSBINEwRb!W*pt!~S;aF#5fyQqQ)+v$D43U(Mf< z?Rp{aar>372NQ)@<6!hxW}@k5O>A9ID(Fq7qkIXdh)4W%YN~6-p!J>3m26Cchymqj z5sd1X^uuNpwz&(Lm(-lQ>{iBEYP06+y}fQ5O6UT5w7Z7IYoc+H@`2HT?gvG#ghR4A zS)MdgDb!AqGgBH099fgMoQJCA#CpPFUA$kAJ^CEx>X&&*$WGV$jnw7)9(T&URHJL` ztT^BBLJiCL!77iA9^owQgj@^o`zUz7ZSa%b(JOT-jfx(@$ait)fLfN4{-uMPw#{l| z^8*jRkGayk;k+*xL+w1TIBzHQ)+3tdJ<-zm9JhzhO7#!CRr9({p81J7aotSU=z+Z^ z)TweOL5S25Xy5 zR_gsa2nTJJ^v_bgOL7+**F&?PiA)aK zH(D4&$FYr!sW6Bzo>L4mStfrA%VbZ}?hYW`LfH)_3p-SL#k*Edv9DzHO2yHP|HGs| z=FVzxka}2H7XO#Xk8Q1C3fh!gSa>`El;Ka<@wj+)NbwEhS|eDWW8ynKXzNz8B-M}2 zf75TKHQDZNzxVn_8<93;?UszJ(%hI=7MiG8CA6@|?ApLjF1)rD84lC)y0e$W@m)iU z+)2v9P3W;^g3H~xOwsCRB?e#nJPKW!6GPp&Qv8|TTZW{sI1%?T^L;FLhHv!NrlAxA zDUkvx`yPEwlKeh&59As&2iBaYGP%B~q2(;yE3N=O74hDSG%2d#=cr8C}?6eY@dx6$fcx#uMrpXeX?PQpc5t)E+mGHN`(|8r&$=AV znApBmqm+k6k3%AWlX76Cb9?KE@y3UV&C7mL3ci@r%DKAt8*tY(ly-WimUsLa_v!o? zE@?(Ddl6_ep6@T-q2Hgu4yxCU_@>1wVo?t=tO#$9q1Ud5H#NJj@pkhF?zUx4 z8E;V*%u?;X;HR8MCukxlaA*?T6H^N(5Du@+sy5?TDE8kx2%WV|3;HojfCVK`>p0j% zjUTK>yFDKgx^7DukKFSbw)%tgQHMEmk{?7r7BlwP z)thjkU)1QJ%E{}RX5Tm`aBmrYbYA>=Ki#jfFGn4~7$7rqDyA0xIse4-iUd>dKos8g zQ+Dn$!56s|4z>xLf|q9Zo|wih_r$be>)*+~@+el{_G_4e{?F{go4FB|gN9=l{pp11 zAJ#)V^wi3Kyh>!h8}gRm6_Huh(-IP@()~Nm1P_~UWFP8iwy<;05OC#JdDgRC#VIA` ztV+f@w;?cl#IY07mrE#h-)aNn;baJZ>LUpZqQ%^Mmy)Z_k(J4#YqZlC-Df?=Pp2VA z{k}8MooM$ymj}vZR9HH#SSyMVrl?eS9LaUQU?_vJ<-S0`9Cssb&Z}SYTY>IOQju2~ z$;sM8_DHMci1C5hxMgJ`R*JcScZ`&{OP^5hhEqyn$nJ3;h0?Ur*tafi+|e1nWE8?j z=)Y}=&HXw@hXB_=wwWBgjYMTrp@y=~&gnv}2uhvZsw(RdUc%biTh^n=cEgB{9VQ(4 zNEIlF1hC@by=!ML8^gx9d)0$4Q!k|j*DhW~J1L1MF(t}K?SbSY z&YUOgl8;v^FPMGp`LV+`#n?~(CHwA$Fx`d)R4D%tua>9Z@BAaNkcH|iKYzR`SJ$xUfe| z)Csbn_{@wWx{M}d{)uB0H-jv$i9|)|Tj-`=DEm{zyqGTR1}5Up&{VdZOy8=Z~6(lSApfDRH8}h@{!;nP_~odcL&9t<=84hqO0ez3|1m8?0|{B@+AUp;2tDJLmh( zWpTQ=4vYp$ClA_Thvh)BsN59ch+bu>JNw$>?a-Z&RjYfV+`nc?(u!CD=`ZyAeJ#cL zS?D(!rY~yxe!i!m=L&=oyOnv*3hv+fG zS6$JdS=X<~vXpVL1>cEpO9>P(`^nU~)1gmpsd{bEdYobW%Wt|HDO754w>EBVmFLKq zT=3Xdzx&pkUaWs|jE{E`{p;rmjV#|vQ4;>7p2B7ZY3yGq12fF~8H!M$hCqT)pY8V#=^V1Myg=i;+CXNI*<+`Y(}#9!`;DcXwyyR8oo z=gR_YS(W|!7$!7tEP0NJm8xmJPja8upj;F9@%pFj{;eNv82XF6Y3*bb-$IEiMrFt( z4rXP4L21IGuSi^sa^qY4Fh_j8C{u;~OS9KiQ-hY(Ps3ZGBZIT-72yI6;j96S>btgE z51jH6tT%?fV9-^B7&wQkx-(7Q3mlEi5EjrV-Tq-ZeNTQJZsl(uO(C)hUQ-Zk< zQeJt@albvRs-#tVQ;D^5Y99yeuyBiRwy*{|&#^6FDlaFewrJAQsc-vi-S4~BB-O=d z3U=Hko?p7$sh)b2xpvv^b+28<`C7)efj+G@j_@u7dk6>5tqX%Mlr8D-C zl7|foH{Z2-(dZ*FYptCz;omR;vBTKpz!6ihV*5RcD`t4%;yjA{;|+5BYW!E#McFhX z9?*yWpG*!uO%#?E-l(YX+f!a$!Qbj&_0KoCO?x*wJ3^=a&L}XW0iDTfx%_2aWB&yg z&TaqXu2J+K@>U}%k7jQtl^Cj$({147Pp8N?mvUe>LBeOfwSvX8EblOd<%%URehZ~) zx{&Trm%;wtt$^}saD7s7Bf4w;=x>9j%N3!}UdyOJ`O+(o^9CO-JL|l!zkWbuclgyK zYUbiL(~ei=m&$??F4G_?2t_0+sRV~kwoCrK4SwOTT++0me%-ge)=^%w%b2I13uPDX zpw|)1edWGW9KX#WASJ;fBVa@-;Y_?lvVE)M%V(uo|4i>0ll4NBNUfs0xeMaK#P$Wa zFQJ+reJy4Q^4+i2=bDgSjA;9|HPznkm^#LOrGa3VumG$qot1Xn4`JG!d1GA%M z2Q&x2Gn>6VN^(dh$YeEypvSSLz~xiV=7&XF0X;mXgmC#2UYEsnCA$V98{}r%U=?Plkm)EwOEG){Q?+_J1j|9ag-|q(BW^|3HrerFS~$YL8NY zLV{Wzec2Y1zc;he8ckcZ*;*Whov&B?Aw=OJ`;vX^hsW;y;z=JYt<~vGj_d*`nmWvX zX!_6gc^#;-9X`torhpugzt#I~Uj1TX?KkwA;;OpfBe&KB(n6NUR~ceoofFX3BSuT+ zj8diwvf|fLV=YYE*KOCsB-=!jAj5C#O7WPpt0F4SY?@Q{bz(CjJD4pu4)V=7 zn%2(Rh-==^Y|CI2`l@S51k`E{5MBmdu}LCwB~n0 z0YjgvumgG=I`ajo!=)$ecas$vOSc+7wWwz|Y3wz;u?7NU^aCmGek{~2yfTKJV=!j6 zaXm>Wc?vs6H~psHet#wVUG1Tn0Vu)UJ7P2n)i@G$rQ(i*=L_83**@!<>Hjw4Pjw6Hup7c+wO_dbd&BSc!dp&d!czn!)Z1o+C}*GCOT7)AcKgZ`Z`3 zwEbLdK2LYUA+uN1{9n^-75*MhbZm31z)$04(Dz$e+w>U!l(8;6jAyFr)lna{0-Uyb8CV0<@WfN=+snK*4*HBR8<9xzd>U%P{?7@um7y zNxAWw7i-E!jU)y>dCn{H`WBsx(TZ{kKMISkWItWYEetbGP_fj|*LdFbfoRZk1ef;k zIz^d1=em57w9PjS_O-SvHO6Vw3Z*35&j*K#el-lnTL0Fdc~ykb=tU2Z%U4&CV0u88 zEzOMEi$V&-3rX$^zFGBN=C2E1E%>tBK0E0X$}9O`A~s^KTZ5*fsKDDn0Ems9o6Yh) zCr95vRx}vk&K5gn*5}c6kwy#)JV(CS&CBgT6?(@^Jjh;WJn{zKBh!!)Oa4JSYc>PV zWoA%KK$T6wLxoLa;iJQ4D@%%tLwa>kf?}pSy9LkPAtibg7v<#N$?eSsh>Js1v6^q`0egm*5^J)Bz%ZFG)kaU@BclkrB2>#@E~Y`dAzh;d?RYJ zD&b0xLCwa^NNjhBvHDf{3zN#hcljPp1Xwe!v0dIvOgmQ@*;8ns`-#r>K#F7_eh`Ye z-O+C!eL>umCS)O>syOPQxaPaIO9Iq}kv1OXX(2Awyo&AMmtybYZt^|jmllq?Q7AgZ zZ^~VqJD4kOn_!eDd2lU_&mcAhjd^kZ(4Gi0INCb{-r zJ33z$bwbTTl%jP%4&!STO3kEf)^tl=NjfExClqWBiP~J|#6+vYJ&Lj=_QR`Uq0pO? zR^^QOPvaNfgt5ru(GeBUWzr9?l6{!vH*wAtR6zB6Im&+cjqy8S7N_Td`p)M;7oYi` zvrQEeAFo%Cmp`(XJDMj93=RxQR!tQ~>5HQ8%{R+j;dL}13Z!XhCKjXO@{ujb5Uc4o zBI>vk*?})gH}0rb7E$TN?jp0J(iIEU3H*$KU&g@KgM04<{!6|0Dv9+ZQH}h-cMiU& z?Sh6}5~t_+IR?TRT>A=}4H~B1Md;q!XuPzP9gXZ4XCm3$6%r~a-;pV3o04|yYdC+3 zvNAm3xPhPf*CzycD$)1jJ|wzsH5+j*`1hN*E4$)XRm)iSYg zLHG`Lo*s#zc!^D$b?k%dYK18Irb{1rv`v+De>G=2hACEO%IN;k*JgGveQsS-0VdH& z1r4lGY(8_!rXIh{6jZD>;TzE#$P zS7OU;4$tG_aKv`Cf$2Tmj<5!!HR;L*EU~EQO<@o0Y%bo8()Js^1r2EH6o$|_^f}JE zTBg*71&%c#3^;dLm}Gv@p>l=MeMA ziCn{LQ;Zeo=N6>S1B-K?FX&ony{FJxD{Rhb8`MO-Pj;SKwCr)jSEAAZQ8R%>k|&e~ zUWpua(P+^>=o^T>3IEW4qTfgt06o}?W}TYe(_Zn$Z#SUgk=?*U33j)mkxjwPqsM26 zqTZeB1Qk12S~((KOQ>dkZM&{oIM<$AhWiT}bxht``-!fOA7y9;?VbL_;Brkb>U^i6+3PknX-`>YJ901Ha^zy|`U0E<+B1#bwX0xVJi z7O4P>RDgwR%pw(FkqWR#1z4m4EK&g$p@)f7fJG|6A{Agi`9jVEH2r9J^+*L+qyj8b z0Tu@Z1q%xWwuypNfJG|6A{Ahf3b058Sfm0hQUMmJ0E<+BMJm7|6=0DHut)`1qyj8b z0T!tMi&TI`D!?KYV37*2NCjA=0xVJi7O4P>RDeY)z#RDeY)z#RDeY)z#Tew;>EvK%Zm^NL|Ms2i26A= z%l<`(4qQq#l>tHpIMPA5lRng604x|FB=j(G5X0|zJ}9UtC@;Z(^-xa!DGXXh16r9O zTEK4^2r(QgDlFOLjfR4vgMor#eu6|P3^F-~fI?* zgDlEq2$pPl2sxZ3zwOz`OOQnn@?Vz?s9{iNL}dXMuyXuGMCB|N2rZ)cC9HUp0nyy~ zyLf9J7aIk|?2LDt+z6Jyv2z5#JH@~5^|OLhWdaDBBpZYZ(Siy1 z3$0EVQT$#Baskoz`{|#V!G6bs>}N;MNCE-XV*fjO&g>w=jugB&iSQvVATIpJ$I@rM zvA$s6{Xr(9Gd_CAB3LYy{|r+V-!jK<3KW!ik^c^pg#y693DHivn?t~@rFt?$VN*wk zS(AJU9R=kFCJKt_nFhwqV6_|(eT?G-JruA;@Mts<0JvO#M}?XTG;P=cty~ZTAchM< z3h%yT#Dcvz$jb=wTAbnCaf3l!;HbtfL!2uhDjr0g9i)<5f4XOmh6m)R{cWs~8*I$% zHo|s69YP7G$;l*y`hcS(_doND+8+VUQHNYW^yDoM$bb`gT#N}w@&3J%rrLqD^ZsXT6R!m}FQ94xaTXX5z}@q&H*bVNu8gM$+gD2rqLV?`KwBq?v1vDg9h7gxJ7E{JUtm@P*|ESo z-uBE8Kj=l^c?}_q@UgKU+qb(14l!(jI6K6~{RrqwLkKxy!k!lgThtmv6uTw=nMrp; zBl^og29*D~zcfb>P$vOYB4EPk&-L%y))XuPooff3vpeIQ?>GVa{ z7h}OuvOWXNn?8o(0(_VLT<9w=JIH^6uDtu73oSQ~z<-cNg#iA>5Mo4+K3oEO^mOsq zMgnMF{yV-Fmq8oD3c@BSk4gZHAKO-7Hj8fvn^fALoBu>s`oGJ#?9EW#H_T?i7RJ?GX&+ zU`R$Imx7gOCuut4z=JNFz}D4iClMszIFEv2aK=$C8AO9Q^5BJrwZ#+8H{A?+%l<#B zmw*ziPa1$`5STl_pq08NBJ&_r2!x)Et@bJiC_F;Ld)KP~`qrrqFHSm+&@j_1Q&F2D zI1`1zNqaVbcx{AWIf>A4s!2tVD%cERgGFe#GmR-Vfqp?A|@36%#phG)l5#1+8;i_i#iKV^{Rq6eaw zkROfkOgM(IbtpQaj)S-9*Z;YfQX>)7Tvfnm1^4Lz_zUez48kY%CPH{jhIiPCw)%4n z*x7la|4xe1LA)xT!3}>~&t$1xFc=;J+;9uMjN95gS2upaoKK^uTQ=(HZ6t1KQ_N4RDNT zK&K4P+=LhU5LB?}j9|gh0a+&d5ydBw7(Pa^Fk9gu!Ul`Ph$=+7U@_hZq8Ju+;r`ce zioHMwukW@0xt$Frj-iN1jG$rA18D}PVKxOI_X!&Isn82=J`V;E_;dThRd;>@H?1Kr~#xWiTXmJMvIy@Z1Ta+>Y3Fo(u0ocGvOojpO z+@u&+0a>>|R_ikZOYrklC3s+l;j2(NSOdWeLG?d(^Vs1jJS;lHy+$qk@h}9$!vgu) zne_JeDLgD}BSyf|2z0m;4bWEqJBG(`8Ua{^0hTdN0bqd{VGFnp+Hi5s+7OW#0l+l| z0VViwKx#i2_25AlK2ixV69w^K6AdEf!c7-VK+`?4Q?$o{7v9N9O39rZu#-JtC(kYf z4Hr&Tf<=*^1BhN^eT|8h>i_V(t{1cOgc{65B?p!X^jzhxQIRcsTzjgpO2pXcN~v4IfaKk zTEm+L0xiL|@0g#m9oB-mBs{Fc2)Ck(e*ZhHA6cKO1bfoPg5lc;P2+)TIS4tLhQo>d z`0*OvDNm0Dtt9Xg{%@qWaXzU7z@NKeocz=8HU1s$9X(IsVKE=kDFz#`Q+eK}Y_K4Y z3FFEiFa|y-Kq%0D`<|Fjf;|k<+-LFe-@*Pc_E{jXt_gY~_vMt`6@1=@kLP#Z zHUEF-7D=n8@Kaz$0p}~&nhgbhYk_>`J16#&Bm?H-B%ZL_zmp7&{gXNXEYpBb&0IpC zJY9f52b`KjzfJ*8at;_P;NlKm$>} z?nc5YU++!eL;Gh65(PQNBUYDGPml$I11klS4F!r||HM1BOReG*tX|#&N`X3J=dX;0|B)0UiFyb8KUU zj|N|oF($BX1daxcz_AG%XckAs1uU=sSq=Az788J=>mW!<wjf^Pj*I%PjeL|~*90|4c+`)L@ll0JBTy{v;wWe4qC~ z_P-O6CT#@X%^yreV9-3nQh|RbBK<}%s5BrR045>~AQaFD0Q=4w3M;+}I8~hclZn7= zVUXteUtk{dzxxR4VF>((1#puZmWj~8@Hkr1n*Yv38i5U1t8h3x5rH@TE)Z<`apWng zlSBjtnE0ON@$W>0C-zh&SR#TA!;8`5i(~-_R^Xx$kbD9-&O{I$wz>zlngE>G5m^U} zVAePa=igaJS{4E?9R%S*(6|MGG<~_JXkZBk7K~=V)Flq+R{$?RPvMFEIO9OnzZVSF z=d3)jpUN&^B)TROQHbnf8Qg1xT^#u6!MFZlb|4`HBv`9Ewh;n-O5ps1+4vvSG$AsH z=oiO!YD5wNubUkT)@5ovwh;oA9N@MpeCr_Vgu zIOwPB@XP^b*C-9m_;=csT$9%YRoxQ4yfQLIc)$q6wc1wMXKOrAR07%7w9(wU0Y)2_zge?;S zAFW_E?c1n6|K4?YDS*K9#{V58jd+mevIwkL0gz5S6Z7HiyoUiEikbR5*-D|Cveo(vsebsJovZ&{v2{fX+Zwr94&s=hFsL+eHT_R2`|Cx}V@L4m+8o>slsU8UU|I=O`$0GX^}7%jIP3D>qVB(; zEYFUi#6b2K2IiTi8}_~y(4qq!{nm)U#YsbOlL)}utDFv;Z*Y4v%pMHxSHhZv*#Ug| zKd;hoYkowDf%`ZuV8(s*jEiMUC-|gZUOdE32#oJ=#bgE@+)oj60$*^RsUy8|QU_T4 z+lKT*%?$~#jSjGlv%`>03dm$aM1Ys~QSnds6W4n*Cb>~i&^-U^lPJY89s&qS|2e+^ z`%}ID?t_~=3@;93N&k5-rL^a)*8;j;=kj0I(UlNTXe%lv!WG!o5n;;?%D<^;JrVf3 z=6~LVger}G8sS1g$#?%Rb+s1)x@-=<2!iE-QxSQd|7M-fML^%&1zBNG%eJvEpM_9R z4)6b$^>zUQDi#2;!X~D<*^>IdS?fk%Pzm5d2KXi(2K^kXe`6kGMTz(?tI9YGDuaLa zL;&)P$(d=6JY%8-AkUa=Yaq{&zK<3n83d? zfo%^W&zK<3m>`ZPBF~s0P5_;}je^}D0P>8A Date: Mon, 30 Sep 2019 14:56:33 -0700 Subject: [PATCH 345/366] Properly use mixins to implement Watchdog --- .../worldedit/fabric/FabricPlatform.java | 8 ++-- .../worldedit/fabric/FabricWatchdog.java | 39 ------------------- .../fabric/mixin/MixinMinecraftServer.java | 15 ++++--- .../src/main/resources/worldedit.mixins.json | 2 +- 4 files changed, 15 insertions(+), 49 deletions(-) delete mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java index f67fdcc59..beb6d5208 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlatform.java @@ -26,7 +26,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.MultiUserPlatform; import com.sk89q.worldedit.extension.platform.Preference; -import com.sk89q.worldedit.fabric.mixin.MixinMinecraftServer; +import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.registry.Registries; @@ -58,7 +58,7 @@ class FabricPlatform extends AbstractPlatform implements MultiUserPlatform { private final FabricWorldEdit mod; private final MinecraftServer server; private final FabricDataFixer dataFixer; - private final @Nullable FabricWatchdog watchdog; + private final @Nullable Watchdog watchdog; private boolean hookingEvents = false; FabricPlatform(FabricWorldEdit mod, MinecraftServer server) { @@ -66,7 +66,7 @@ class FabricPlatform extends AbstractPlatform implements MultiUserPlatform { this.server = server; this.dataFixer = new FabricDataFixer(getDataVersion()); this.watchdog = server instanceof MinecraftDedicatedServer - ? new FabricWatchdog((MinecraftDedicatedServer) server) : null; + ? (Watchdog) server : null; } boolean isHookingEvents() { @@ -105,7 +105,7 @@ class FabricPlatform extends AbstractPlatform implements MultiUserPlatform { @Override @Nullable - public FabricWatchdog getWatchdog() { + public Watchdog getWatchdog() { return watchdog; } diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java deleted file mode 100644 index b0f25c685..000000000 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricWatchdog.java +++ /dev/null @@ -1,39 +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 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.fabric; - -import com.sk89q.worldedit.extension.platform.Watchdog; -import com.sk89q.worldedit.fabric.mixin.MixinMinecraftServer; -import net.minecraft.server.dedicated.MinecraftDedicatedServer; -import net.minecraft.util.SystemUtil; - -class FabricWatchdog implements Watchdog { - - private final MinecraftDedicatedServer server; - - FabricWatchdog(MinecraftDedicatedServer server) { - this.server = server; - } - - @Override - public void tick() { - ((MixinMinecraftServer) (Object) server).timeReference = SystemUtil.getMeasuringTimeMs(); - } -} diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java index de54985b8..7b78b6cd6 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java @@ -19,21 +19,26 @@ package com.sk89q.worldedit.fabric.mixin; +import com.sk89q.worldedit.extension.platform.Watchdog; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.ServerTask; -import net.minecraft.server.command.CommandOutput; import net.minecraft.util.NonBlockingThreadExecutor; -import net.minecraft.util.snooper.SnooperListener; +import net.minecraft.util.SystemUtil; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @Mixin(MinecraftServer.class) -public abstract class MixinMinecraftServer extends NonBlockingThreadExecutor implements SnooperListener, CommandOutput, AutoCloseable, Runnable { +public abstract class MixinMinecraftServer extends NonBlockingThreadExecutor implements Watchdog { public MixinMinecraftServer(String name) { super(name); } @Shadow - public long timeReference; + private long timeReference; + + @Override + public void tick() { + timeReference = SystemUtil.getMeasuringTimeMs(); + } + } diff --git a/worldedit-fabric/src/main/resources/worldedit.mixins.json b/worldedit-fabric/src/main/resources/worldedit.mixins.json index ecd0ffd49..fd6cd4f92 100644 --- a/worldedit-fabric/src/main/resources/worldedit.mixins.json +++ b/worldedit-fabric/src/main/resources/worldedit.mixins.json @@ -11,4 +11,4 @@ "injectors": { "defaultRequire": 1 } -} \ No newline at end of file +} From 3093c45675be1fa698916fea6889fab73552b500 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Mon, 30 Sep 2019 14:59:51 -0700 Subject: [PATCH 346/366] Restore mixin generic --- .../com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java index 7b78b6cd6..ab73faf79 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/mixin/MixinMinecraftServer.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.fabric.mixin; import com.sk89q.worldedit.extension.platform.Watchdog; +import net.minecraft.server.ServerTask; import net.minecraft.server.MinecraftServer; import net.minecraft.util.NonBlockingThreadExecutor; import net.minecraft.util.SystemUtil; @@ -27,7 +28,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @Mixin(MinecraftServer.class) -public abstract class MixinMinecraftServer extends NonBlockingThreadExecutor implements Watchdog { +public abstract class MixinMinecraftServer extends NonBlockingThreadExecutor implements Watchdog { public MixinMinecraftServer(String name) { super(name); From 91f92a46fe88ef7fae990c9b6f9bc906d57e300a Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 30 Sep 2019 18:28:13 -0400 Subject: [PATCH 347/366] Apply watchdog mode to undo/redo. Abstract EditSession creation logic. --- .../com/sk89q/worldedit/LocalSession.java | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 9ac50111e..47042a88d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -239,12 +239,7 @@ public class LocalSession { EditSession editSession = history.get(historyPointer); try (EditSession newEditSession = WorldEdit.getInstance().getEditSessionFactory() .getEditSession(editSession.getWorld(), -1, newBlockBag, actor)) { - newEditSession.enableStandardMode(); - newEditSession.setReorderMode(reorderMode); - newEditSession.setFastMode(fastMode); - if (newEditSession.getSurvivalExtent() != null) { - newEditSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); - } + prepareEditingExtents(editSession, actor); editSession.undo(newEditSession); } return editSession; @@ -267,12 +262,7 @@ public class LocalSession { EditSession editSession = history.get(historyPointer); try (EditSession newEditSession = WorldEdit.getInstance().getEditSessionFactory() .getEditSession(editSession.getWorld(), -1, newBlockBag, actor)) { - newEditSession.enableStandardMode(); - newEditSession.setReorderMode(reorderMode); - newEditSession.setFastMode(fastMode); - if (newEditSession.getSurvivalExtent() != null) { - newEditSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); - } + prepareEditingExtents(editSession, actor); editSession.redo(newEditSession); } ++historyPointer; @@ -954,15 +944,19 @@ public class LocalSession { } Request.request().setEditSession(editSession); + editSession.setMask(mask); + prepareEditingExtents(editSession, actor); + + return editSession; + } + + private void prepareEditingExtents(EditSession editSession, Actor actor) { editSession.setFastMode(fastMode); editSession.setReorderMode(reorderMode); - editSession.setMask(mask); if (editSession.getSurvivalExtent() != null) { editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt")); } editSession.setTickingWatchdog(tickingWatchdog); - - return editSession; } /** From 03c0cce53e2fe8cf5ce6a0575a023be5eb05b5a3 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 5 Oct 2019 02:06:18 -0700 Subject: [PATCH 348/366] Update to Piston 0.5.2 + Doctools/Deprecation improvements (#523) * Update to Piston 0.5.2 * [Doctools] Fix output, be verbose about deprecations * Improve deprecation system, doctools output --- buildSrc/src/main/kotlin/Versions.kt | 2 +- .../bukkit/BukkitBlockCommandSender.java | 3 +- .../bukkit/BukkitCommandInspector.java | 2 +- .../worldedit/bukkit/BukkitCommandSender.java | 3 +- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 3 +- .../bukkit/BukkitServerInterface.java | 2 +- .../sk89q/worldedit/cli/CLICommandSender.java | 3 +- .../internal/util/DocumentationPrinter.kt | 52 ++++++++------ .../internal/util/RstWorldEditText.kt | 69 +++++++++++++++++++ .../sk89q/worldedit/command/ToolCommands.java | 2 +- .../platform/PlatformCommandManager.java | 7 +- .../internal/command/CommandUtil.java | 63 +++++++++++++++-- .../util/formatting/WorldEditText.java | 35 +++++----- .../formatting/component/CommandUsageBox.java | 12 ++-- .../sk89q/worldedit/fabric/FabricPlayer.java | 3 +- .../sk89q/worldedit/forge/ForgePlayer.java | 3 +- .../worldedit/sponge/SpongeCommandSender.java | 3 +- .../sk89q/worldedit/sponge/SpongePlayer.java | 3 +- .../worldedit/sponge/SpongeTextAdapter.java | 2 + 19 files changed, 205 insertions(+), 67 deletions(-) create mode 100644 worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/RstWorldEditText.kt rename worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitTextAdapter.java => worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/WorldEditText.java (54%) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 391029752..d9d0e643a 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -3,7 +3,7 @@ import org.gradle.api.Project object Versions { const val TEXT = "3.0.1" const val TEXT_EXTRAS = "3.0.2" - const val PISTON = "0.4.3" + const val PISTON = "0.5.2" const val AUTO_VALUE = "1.6.5" const val JUNIT = "5.5.0" const val MOCKITO = "3.0.0" diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java index d87462322..fe5114cb1 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java @@ -27,6 +27,7 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; @@ -90,7 +91,7 @@ public class BukkitBlockCommandSender extends AbstractNonPlayerActor implements @Override public void print(Component component) { - TextAdapter.sendComponent(sender, component); + TextAdapter.sendComponent(sender, WorldEditText.format(component)); } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java index 972f7f5e1..de2a5ffa1 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandInspector.java @@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory; import java.util.Optional; import static com.google.common.base.Preconditions.checkNotNull; -import static com.sk89q.worldedit.bukkit.BukkitTextAdapter.reduceToText; +import static com.sk89q.worldedit.util.formatting.WorldEditText.reduceToText; class BukkitCommandInspector implements CommandInspector { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java index f1ac08599..75d5aa903 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java @@ -25,6 +25,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.extension.platform.AbstractNonPlayerActor; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter; import org.bukkit.command.CommandSender; @@ -93,7 +94,7 @@ public class BukkitCommandSender extends AbstractNonPlayerActor { @Override public void print(Component component) { - TextAdapter.sendComponent(sender, component); + TextAdapter.sendComponent(sender, WorldEditText.format(component)); } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java index 3e12279ea..75b9c0ff7 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; +import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; @@ -129,7 +130,7 @@ public class BukkitPlayer extends AbstractPlayerActor { @Override public void print(Component component) { - TextAdapter.sendComponent(player, component); + TextAdapter.sendComponent(player, WorldEditText.format(component)); } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 5bdffb5e9..0fda56974 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -47,7 +47,7 @@ import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.sk89q.worldedit.bukkit.BukkitTextAdapter.reduceToText; +import static com.sk89q.worldedit.util.formatting.WorldEditText.reduceToText; public class BukkitServerInterface implements MultiUserPlatform { public Server server; diff --git a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLICommandSender.java b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLICommandSender.java index 0c9cb22f8..970c11df5 100644 --- a/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLICommandSender.java +++ b/worldedit-cli/src/main/java/com/sk89q/worldedit/cli/CLICommandSender.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.FileDialogUtil; import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer; import org.slf4j.Logger; @@ -96,7 +97,7 @@ public class CLICommandSender implements Actor { @Override public void print(Component component) { - print(PlainComponentSerializer.INSTANCE.serialize(component)); + print(PlainComponentSerializer.INSTANCE.serialize(WorldEditText.format(component))); } @Override diff --git a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt index c6b94b86b..931c665ba 100644 --- a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/DocumentationPrinter.kt @@ -24,7 +24,6 @@ import com.sk89q.worldedit.WorldEdit import com.sk89q.worldedit.command.BiomeCommands import com.sk89q.worldedit.command.ChunkCommands import com.sk89q.worldedit.command.ClipboardCommands -import com.sk89q.worldedit.command.ExpandCommands import com.sk89q.worldedit.command.GeneralCommands import com.sk89q.worldedit.command.GenerationCommands import com.sk89q.worldedit.command.HistoryCommands @@ -37,11 +36,10 @@ import com.sk89q.worldedit.command.ToolCommands import com.sk89q.worldedit.command.ToolUtilCommands import com.sk89q.worldedit.command.UtilityCommands import com.sk89q.worldedit.command.util.PermissionCondition +import com.sk89q.worldedit.internal.command.CommandUtil import com.sk89q.worldedit.util.formatting.text.TextComponent -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent -import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer import org.enginehub.piston.Command -import org.enginehub.piston.TextConfig +import org.enginehub.piston.config.TextConfig import org.enginehub.piston.part.SubCommandPart import org.enginehub.piston.util.HelpGenerator import java.nio.file.Files @@ -52,7 +50,6 @@ import kotlin.streams.toList class DocumentationPrinter private constructor() { private val nameRegex = Regex("name = \"(.+?)\"") - private val serializer = PlainComponentSerializer({ "" }, TranslatableComponent::key) private val commands = WorldEdit.getInstance().platformManager.platformCommandManager.commandManager.allCommands .map { it.name to it }.toList().toMap() private val cmdOutput = StringBuilder() @@ -111,6 +108,7 @@ class DocumentationPrinter private constructor() { } dumpSection("Tool Commands") { + yield("tool") yieldAllCommandsIn() yieldAllCommandsIn() } @@ -216,7 +214,7 @@ Other Permissions private fun dumpSection(title: String, addCommandNames: suspend SequenceScope.() -> Unit) { cmdOutput.append("\n").append(title).append("\n").append(Strings.repeat("~", title.length)).append("\n") - val prefix = TextConfig.getCommandPrefix() + val prefix = reduceToRst(TextConfig.commandPrefixValue()) val commands = sequence(addCommandNames).map { this.commands.getValue(it) }.toList() matchedCommands.addAll(commands.map { it.name }) @@ -269,14 +267,19 @@ Other Permissions } cmdOutput.appendln() cmdOutput.appendln(" :class: command-topic").appendln() + CommandUtil.deprecationWarning(command).ifPresent { warning -> + cmdOutput.appendln(""" + | .. WARNING:: + | ${reduceToRst(warning).makeRstSafe("\n\n")} + """.trimMargin()) + } cmdOutput.appendln(""" | .. csv-table:: | :widths: 8, 15 """.trimMargin()) cmdOutput.appendln() for ((k, v) in entries) { - val rstSafe = v.trim().replace("\"", "\\\"").replace("\n", "\n" + " ".repeat(2)) - .lineSequence().map { line -> line.ifBlank { "" } }.joinToString(separator = "\n") + val rstSafe = v.makeRstSafe("\n") cmdOutput.append(" ".repeat(2)) .append(k) .append(",") @@ -287,32 +290,39 @@ Other Permissions cmdOutput.appendln() } + private fun String.makeRstSafe(lineJoiner: String) = trim() + .replace("\"", "\\\"").replace("\n", "\n" + " ".repeat(2)) + .lineSequence() + .map { line -> line.ifBlank { "" } } + .joinToString(separator = lineJoiner) + private fun linkSafe(text: String) = text.replace(" ", "-") private fun commandTableEntries(command: Command, parents: Stream): Map { return sequence { val desc = command.description.run { + val footer = CommandUtil.footerWithoutDeprecation(command) when { - command.footer.isPresent -> append( - TextComponent.builder("\n\n").append(command.footer.get()) + footer.isPresent -> append( + TextComponent.builder("\n\n").append(footer.get()) ) else -> this } } - yield("**Description**" to serializer.serialize(desc)) + yield("**Description**" to reduceToRst(desc)) val cond = command.condition if (cond is PermissionCondition && cond.permissions.isNotEmpty()) { val perms = cond.permissions.joinToString(", ") { "``$it``" } yield("**Permissions**" to perms) } - val usage = serializer.serialize(HelpGenerator.create(Stream.concat(parents, Stream.of(command)).toList()).usage) + val usage = reduceToRst(HelpGenerator.create(Stream.concat(parents, Stream.of(command)).toList()).usage) yield("**Usage**" to "``$usage``") // Part descriptions command.parts.filterNot { it is SubCommandPart } .forEach { - val title = "\u2001\u2001``" + serializer.serialize(it.textRepresentation) + "``" - yield(title to serializer.serialize(it.description)) + val title = "\u2001\u2001``" + reduceToRst(it.textRepresentation) + "``" + yield(title to reduceToRst(it.description)) } }.toMap() } @@ -324,13 +334,15 @@ Other Permissions */ @JvmStatic fun main(args: Array) { - val printer = DocumentationPrinter() + try { + val printer = DocumentationPrinter() - printer.writeAllCommands() - writeOutput("commands.rst", printer.cmdOutput.toString()) - writeOutput("permissions.rst", printer.permsOutput.toString()) - - WorldEdit.getInstance().sessionManager.unload() + printer.writeAllCommands() + writeOutput("commands.rst", printer.cmdOutput.toString()) + writeOutput("permissions.rst", printer.permsOutput.toString()) + } finally { + WorldEdit.getInstance().sessionManager.unload() + } } private fun writeOutput(file: String, output: String) { diff --git a/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/RstWorldEditText.kt b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/RstWorldEditText.kt new file mode 100644 index 000000000..2b37700f6 --- /dev/null +++ b/worldedit-core/doctools/src/main/kotlin/com/sk89q/worldedit/internal/util/RstWorldEditText.kt @@ -0,0 +1,69 @@ +package com.sk89q.worldedit.internal.util + +import com.sk89q.worldedit.util.formatting.WorldEditText +import com.sk89q.worldedit.util.formatting.text.Component +import com.sk89q.worldedit.util.formatting.text.TextComponent +import com.sk89q.worldedit.util.formatting.text.TranslatableComponent +import com.sk89q.worldedit.util.formatting.text.event.ClickEvent +import com.sk89q.worldedit.util.formatting.text.format.TextDecoration +import org.enginehub.piston.util.TextHelper + +fun reduceToRst(component: Component): String { + val formatted = WorldEditText.format(component) + return formatAsRst(formatted).toString() +} + +private fun formatAsRst(component: Component, currentDeco: String? = null): CharSequence { + return when (component) { + is TextComponent -> { + val content = StringBuilder(component.content()) + + val deco = when { + // Actions that suggest themselves as commands are marked as code + component.isSuggestingAsCommand(content.toString()) -> "``" + component.decorations().any { it == TextDecoration.BOLD } -> "**" + component.decorations().any { it == TextDecoration.ITALIC } -> "*" + else -> null + } + + component.children().joinTo(content, separator = "") { + formatAsRst(it, deco ?: currentDeco) + } + + deco?.let { + require(currentDeco == null) { + "Nested decorations are hell in RST. \n" + + "Existing: $currentDeco; New: $deco\n" + + "Offender: ${TextHelper.reduceToText(component)}" + } + content.rstDeco(deco) + } + + content + } + is TranslatableComponent -> { + val content = StringBuilder(component.key()) + component.children().joinTo(content, separator = "") { formatAsRst(it, currentDeco) } + content + } + else -> component.children().joinToString(separator = "") { formatAsRst(it, currentDeco) } + } +} + +private fun Component.isSuggestingAsCommand(text: String): Boolean { + val ce = clickEvent() + return when (ce?.action()) { + ClickEvent.Action.RUN_COMMAND, + ClickEvent.Action.SUGGEST_COMMAND -> + ce.value() == text + else -> false + } +} + +private fun StringBuilder.rstDeco(deco: String): StringBuilder = apply { + ensureCapacity(length + deco.length * 2) + val insertionPoint = indexOfFirst { !it.isWhitespace() }.coerceAtLeast(0) + insert(insertionPoint, deco) + val insertionPointEnd = (indexOfLast { !it.isWhitespace() } + 1).takeUnless { it < 1 } ?: length + insert(insertionPointEnd, deco) +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index 29c05676c..9418804b6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -88,7 +88,7 @@ public class ToolCommands { ).build(); } commandManager.register(CommandUtil.deprecate( - command, "Using global tool names is deprecated " + + command, "Global tool names cause conflicts " + "and will be removed in WorldEdit 8", ToolCommands::asNonGlobal )); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java index 2913a277d..2bcddc7f8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformCommandManager.java @@ -106,7 +106,8 @@ import com.sk89q.worldedit.util.logging.LogFormat; import com.sk89q.worldedit.world.World; import org.enginehub.piston.Command; import org.enginehub.piston.CommandManager; -import org.enginehub.piston.TextConfig; +import org.enginehub.piston.config.ConfigHolder; +import org.enginehub.piston.config.TextConfig; import org.enginehub.piston.converter.ArgumentConverters; import org.enginehub.piston.exception.CommandException; import org.enginehub.piston.exception.CommandExecutionException; @@ -152,10 +153,6 @@ public final class PlatformCommandManager { private static final java.util.logging.Logger COMMAND_LOG = java.util.logging.Logger.getLogger("com.sk89q.worldedit.CommandLog"); - static { - TextConfig.setCommandPrefix("/"); - } - private final WorldEdit worldEdit; private final PlatformManager platformManager; private final CommandManagerServiceImpl commandManagerService; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java index d1690fc24..64c0324a4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/command/CommandUtil.java @@ -42,6 +42,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkState; @@ -49,11 +50,16 @@ import static java.util.stream.Collectors.toList; public class CommandUtil { - private static Component makeDeprecatedFooter(Component newCommand) { - return TextComponent.builder("This command is deprecated. Use ", TextColor.GOLD) - .decoration(TextDecoration.ITALIC, true) + private static final Component DEPRECATION_MARKER = TextComponent.of("This command is deprecated."); + + private static Component makeDeprecatedFooter(String reason, Component newCommand) { + return TextComponent.builder() + .append(DEPRECATION_MARKER) + .append(" " + reason + ".") + .append(TextComponent.newline()) + .append(TextComponent.of("Use ", TextColor.GOLD, TextDecoration.ITALIC)) .append(newCommand) - .append(" instead.") + .append(TextComponent.of(" instead.", TextColor.GOLD, TextDecoration.ITALIC)) .build(); } @@ -66,6 +72,7 @@ public class CommandUtil { public static Command deprecate(Command command, String reason, NewCommandGenerator newCommandGenerator) { Component deprecatedWarning = makeDeprecatedFooter( + reason, newCommandSuggestion(newCommandGenerator, NoInputCommandParameters.builder().build(), command) @@ -80,6 +87,54 @@ public class CommandUtil { .build(); } + public static Optional footerWithoutDeprecation(Command command) { + return command.getFooter() + .filter(footer -> anyComponent(footer, Predicate.isEqual(DEPRECATION_MARKER))) + .map(footer -> Optional.of( + replaceDeprecation(footer) + )) + .orElseGet(command::getFooter); + } + + public static Optional deprecationWarning(Command command) { + return command.getFooter() + .map(CommandUtil::extractDeprecation) + .orElseGet(command::getFooter); + } + + public static boolean isDeprecated(Command command) { + return command.getFooter() + .filter(footer -> anyComponent(footer, Predicate.isEqual(DEPRECATION_MARKER))) + .isPresent(); + } + + private static boolean anyComponent(Component component, Predicate test) { + return test.test(component) || component.children().stream() + .anyMatch(x -> anyComponent(x, test)); + } + + private static Component replaceDeprecation(Component component) { + if (component.children().stream().anyMatch(Predicate.isEqual(DEPRECATION_MARKER))) { + return TextComponent.empty(); + } + return component.children( + component.children().stream() + .map(CommandUtil::replaceDeprecation) + .collect(toList()) + ); + } + + private static Optional extractDeprecation(Component component) { + if (component.children().stream().anyMatch(Predicate.isEqual(DEPRECATION_MARKER))) { + return Optional.of(component); + } + return component.children().stream() + .map(CommandUtil::extractDeprecation) + .filter(Optional::isPresent) + .map(Optional::get) + .findAny(); + } + private static int deprecatedCommandWarning( CommandParameters parameters, Command command, diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitTextAdapter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/WorldEditText.java similarity index 54% rename from worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitTextAdapter.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/WorldEditText.java index fba2c2b1e..897a3fa46 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitTextAdapter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/WorldEditText.java @@ -17,32 +17,29 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.bukkit; +package com.sk89q.worldedit.util.formatting; import com.sk89q.worldedit.util.formatting.text.Component; -import com.sk89q.worldedit.util.formatting.text.TextComponent; -import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; +import org.enginehub.piston.config.ConfigHolder; +import org.enginehub.piston.config.TextConfig; +import org.enginehub.piston.util.TextHelper; -public class BukkitTextAdapter { +public class WorldEditText { + public static final ConfigHolder CONFIG_HOLDER = ConfigHolder.create(); + + static { + CONFIG_HOLDER.getConfig(TextConfig.commandPrefix()).setValue("/"); + } + + public static Component format(Component component) { + return CONFIG_HOLDER.replace(component); + } public static String reduceToText(Component component) { - StringBuilder text = new StringBuilder(); - appendTextTo(text, component); - return text.toString(); + return TextHelper.reduceToText(format(component)); } - private static void appendTextTo(StringBuilder builder, Component component) { - if (component instanceof TextComponent) { - builder.append(((TextComponent) component).content()); - } else if (component instanceof TranslatableComponent) { - builder.append(((TranslatableComponent) component).key()); - } - for (Component child : component.children()) { - appendTextTo(builder, child); - } - } - - private BukkitTextAdapter() { + private WorldEditText() { } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java index 579bd44a9..ed5ab2db2 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/formatting/component/CommandUsageBox.java @@ -24,9 +24,9 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.format.TextDecoration; -import org.enginehub.piston.ColorConfig; import org.enginehub.piston.Command; import org.enginehub.piston.CommandParameters; +import org.enginehub.piston.config.ColorConfig; import org.enginehub.piston.util.HelpGenerator; import javax.annotation.Nullable; @@ -72,15 +72,13 @@ public class CommandUsageBox extends TextComponentProducer { .append(HelpGenerator.create(commands).getFullHelp()); if (getSubCommands(Iterables.getLast(commands)).size() > 0) { boxContent.append(TextComponent.newline()) - .append(TextComponent.builder("> ") - .color(ColorConfig.getHelpText()) - .append(TextComponent.builder("List Subcommands") - .color(ColorConfig.getMainText()) + .append(ColorConfig.helpText().wrap(TextComponent.builder("> ") + .append(ColorConfig.mainText().wrap(TextComponent.builder("List Subcommands") .decoration(TextDecoration.ITALIC, true) .clickEvent(ClickEvent.runCommand(helpRootCommand + " -s " + commandString)) .hoverEvent(HoverEvent.showText(TextComponent.of("List all subcommands of this command"))) - .build()) - .build()); + .build())) + .build())); } MessageBox box = new MessageBox("Help for " + commandString, boxContent); diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java index 6bd1171d7..60003a259 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/FabricPlayer.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer; import com.sk89q.worldedit.world.World; @@ -151,7 +152,7 @@ public class FabricPlayer extends AbstractPlayerActor { @Override public void print(Component component) { - this.player.sendMessage(Text.Serializer.fromJson(GsonComponentSerializer.INSTANCE.serialize(component))); + this.player.sendMessage(Text.Serializer.fromJson(GsonComponentSerializer.INSTANCE.serialize(WorldEditText.format(component)))); } private void sendColorized(String msg, Formatting formatting) { diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java index 94dfb8c10..22250e0de 100644 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/ForgePlayer.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer; import com.sk89q.worldedit.world.World; @@ -152,7 +153,7 @@ public class ForgePlayer extends AbstractPlayerActor { @Override public void print(Component component) { - this.player.sendMessage(ITextComponent.Serializer.fromJson(GsonComponentSerializer.INSTANCE.serialize(component))); + this.player.sendMessage(ITextComponent.Serializer.fromJson(GsonComponentSerializer.INSTANCE.serialize(WorldEditText.format(component)))); } private void sendColorized(String msg, TextFormatting formatting) { diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java index e6eac1f83..4f8b7fa44 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeCommandSender.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.auth.AuthorizationException; +import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.adapter.spongeapi.TextAdapter; import org.spongepowered.api.command.CommandSource; @@ -93,7 +94,7 @@ public class SpongeCommandSender implements Actor { @Override public void print(Component component) { - TextAdapter.sendComponent(sender, component); + TextAdapter.sendComponent(sender, WorldEditText.format(component)); } private void sendColorized(String msg, TextColor formatting) { diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java index 3a5f94933..aa0056710 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongePlayer.java @@ -31,6 +31,7 @@ import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.session.SessionKey; import com.sk89q.worldedit.util.HandSide; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.adapter.spongeapi.TextAdapter; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -153,7 +154,7 @@ public class SpongePlayer extends AbstractPlayerActor { @Override public void print(Component component) { - TextAdapter.sendComponent(player, component); + TextAdapter.sendComponent(player, WorldEditText.format(component)); } private void sendColorized(String msg, TextColor formatting) { diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeTextAdapter.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeTextAdapter.java index 836006803..4e7b5c2fb 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeTextAdapter.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeTextAdapter.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.sponge; +import com.sk89q.worldedit.util.formatting.WorldEditText; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.serializer.gson.GsonComponentSerializer; import org.spongepowered.api.text.Text; @@ -27,6 +28,7 @@ import org.spongepowered.api.text.serializer.TextSerializers; public class SpongeTextAdapter { public static Text convert(Component component) { + component = WorldEditText.format(component); return TextSerializers.JSON.deserialize(GsonComponentSerializer.INSTANCE.serialize(component)); } From ffbb25f1eabf32c43b03987d47a266bbf1aacda3 Mon Sep 17 00:00:00 2001 From: Matt <4009945+MattBDev@users.noreply.github.com> Date: Fri, 11 Oct 2019 13:42:07 -0400 Subject: [PATCH 349/366] Fixed snapshot typo --- .../main/java/com/sk89q/worldedit/command/SnapshotCommands.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java index da839703f..fe197d04b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SnapshotCommands.java @@ -111,7 +111,7 @@ public class SnapshotCommands { ) @CommandPermissions("worldedit.snapshots.restore") public void use(Actor actor, World world, LocalSession session, - @Arg(desc = "Snapeshot to use") + @Arg(desc = "Snapshot to use") String name) throws WorldEditException { LocalConfiguration config = we.getConfiguration(); From 7d52374fc01cf9c29cd9fe7a59b0d101b535886a Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 13 Oct 2019 02:02:47 -0700 Subject: [PATCH 350/366] Add initial ANTLR setup + lex/parser --- worldedit-core/build.gradle.kts | 27 +++ .../com/sk89q/worldedit/antlr/Expression.g4 | 186 ++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index a20b254f8..19dcecc05 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -1,7 +1,10 @@ +import org.gradle.plugins.ide.idea.model.IdeaModel + plugins { id("java-library") id("net.ltgt.apt-eclipse") id("net.ltgt.apt-idea") + id("antlr") } applyPlatformAndCoreConfiguration() @@ -23,6 +26,10 @@ dependencies { "compile"("org.slf4j:slf4j-api:1.7.26") "compile"("it.unimi.dsi:fastutil:8.2.1") + val antlrVersion = "4.7.2" + "antlr"("org.antlr:antlr4:$antlrVersion") + "implementation"("org.antlr:antlr4-runtime:$antlrVersion") + "compileOnly"(project(":worldedit-libs:core:ap")) "annotationProcessor"(project(":worldedit-libs:core:ap")) // ensure this is on the classpath for the AP @@ -36,6 +43,26 @@ tasks.withType().configureEach { options.compilerArgs.add("-Aarg.name.key.prefix=") } +tasks.named("generateGrammarSource").configure { + val pkg = "com.sk89q.worldedit.antlr" + outputDirectory = file("build/generated-src/antlr/main/${pkg.replace('.', '/')}") + arguments = listOf( + "-visitor", "-package", pkg, + "-Xexact-output-dir" + ) +} + +// Give intellij info about where ANTLR code comes from +plugins.withId("idea") { + configure { + afterEvaluate { + module.sourceDirs.add(file("src/main/antlr")) + module.sourceDirs.add(file("build/generated-src/antlr/main")) + module.generatedSourceDirs.add(file("build/generated-src/antlr/main")) + } + } +} + sourceSets { main { java { diff --git a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 new file mode 100644 index 000000000..254e0bf46 --- /dev/null +++ b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 @@ -0,0 +1,186 @@ +grammar Expression; + +// Lexer tokens: + +PLUS : '+' ; +MINUS : '-' ; +TIMES : '*' ; +DIVIDE : '/' ; +MODULO : '%' ; +POWER : '^' | '**' ; +LEFT_SHIFT : '<<' ; +RIGHT_SHIFT : '>>' ; +ASSIGN : '=' ; +COMPLEMENT : '~' ; + +PLUS_ASSIGN : '+=' ; +MINUS_ASSIGN : '-=' ; +TIMES_ASSIGN : '*=' ; +DIVIDE_ASSIGN : '/=' ; +MODULO_ASSIGN : '%=' ; +POWER_ASSIGN : '^=' ; + +EQUAL : '==' ; +NOT_EQUAL : '!=' ; +NEAR : '~=' ; +LESS_THAN : '<' ; +LESS_THAN_OR_EQUAL : '<=' ; +GREATER_THAN : '>' ; +GREATER_THAN_OR_EQUAL : '>=' ; +// SC = "Short Circuit" +// Non-SC variants not currently implemented. +AND_SC : '&&' ; +OR_SC : '||' ; + +INCREMENT : '++' ; +DECREMENT : '--' ; + +COMMA : ',' ; +OPEN_PAREN : '(' ; +CLOSE_PAREN : ')' ; +OPEN_BRACKET : '{' ; +CLOSE_BRACKET : '}' ; +SEMI_COLON : ';' ; +QUESTION_MARK : '?' ; +COLON : ':' ; +EXCLAMATION_MARK : '!' ; + +IF : 'if' ; +ELSE : 'else' ; +WHILE : 'while' ; +DO : 'do' ; +FOR : 'for' ; +BREAK : 'break' ; +CONTINUE : 'continue' ; +RETURN : 'return' ; +SWITCH : 'switch' ; +CASE : 'case' ; +DEFAULT : 'default' ; + +fragment DIGIT : [0-9] ; +fragment SIGN : [+-] ; +fragment EXP_CHAR : [eE] ; +fragment DECIMAL : '.' DIGIT+ ( EXP_CHAR SIGN? DIGIT+ )? ; + +// All numbers are treated the same. No int/dec divide. +NUMBER : SIGN? ( DIGIT+ DECIMAL? | DECIMAL ) ; + +ID : [A-Za-z] [0-9A-Za-z_]* ; + +WS : [ \t\r\n\u000C]+ -> skip ; + +// Parser rules: + +/** + * All statements parseable from the input. Forces consumption of EOF token. + */ +allStatements : statements EOF ; + +statements : statement+ ; + +statement + : block + | ifStatement + | whileStatement + | doStatement + | forStatement + | breakStatement + | continueStatement + | returnStatement + | switchStatement + | expressionStatement + | SEMI_COLON + ; + +block : '{' statements '}' ; + +ifStatement : IF '(' expression ')' statement ( ELSE statement ) ; + +whileStatement : WHILE '(' expression ')' statement ; + +doStatement : DO statement WHILE '(' expression ')' SEMI_COLON ; + +forStatement + : FOR '(' + // C-style for loop + ( expression ';' expression ';' expression + // Range for loop + | ID ASSIGN ID ',' ID + ) + ')' statement ; + +breakStatement : BREAK ; + +continueStatement : CONTINUE ; + +returnStatement : RETURN expression? ; + +switchStatement : SWITCH '(' expression ')' '{' (switchLabel ':' statements )+ '}' ; + +switchLabel + : CASE constantExpression + | DEFAULT + ; + +expressionStatement : expression SEMI_COLON ; + +expression + : constantExpression + | functionCall + | identifierExpression + | '(' expression ')' + | unaryOp expression + | identifierExpression binaryAssignOp expression + | expression binaryOp expression + | expression postUnaryOp + ; + +constantExpression : NUMBER ; + +functionCall : ID '(' (expression ( ',' expression )*)? ')' ; + +identifierExpression : ID ; + +unaryOp + : MINUS + | EXCLAMATION_MARK + | COMPLEMENT + | INCREMENT + | DECREMENT + ; + +postUnaryOp + : INCREMENT + | DECREMENT + | EXCLAMATION_MARK + ; + +binaryOp + : POWER + | TIMES + | DIVIDE + | MODULO + | PLUS + | MINUS + | LEFT_SHIFT + | RIGHT_SHIFT + | LESS_THAN + | GREATER_THAN + | LESS_THAN_OR_EQUAL + | GREATER_THAN_OR_EQUAL + | EQUAL + | NOT_EQUAL + | NEAR + | AND_SC + | OR_SC + ; + +binaryAssignOp + : ASSIGN + | PLUS_ASSIGN + | MINUS_ASSIGN + | TIMES_ASSIGN + | DIVIDE_ASSIGN + | MODULO_ASSIGN + | POWER_ASSIGN + ; From 9f1e7cdaafd83ef7465ee581e48fe13f83f3373c Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 13 Oct 2019 02:20:10 -0700 Subject: [PATCH 351/366] Small modifications for better visitors --- .../com/sk89q/worldedit/antlr/Expression.g4 | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 index 254e0bf46..b244f2c64 100644 --- a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 +++ b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 @@ -79,17 +79,17 @@ allStatements : statements EOF ; statements : statement+ ; statement - : block - | ifStatement - | whileStatement - | doStatement - | forStatement - | breakStatement - | continueStatement - | returnStatement - | switchStatement - | expressionStatement - | SEMI_COLON + : block # BlockStmt + | ifStatement # IfStmt + | whileStatement # WhileStmt + | doStatement # DoStmt + | forStatement # ForStmt + | breakStatement # BreakStmt + | continueStatement # ContinueStmt + | returnStatement # ReturnStmt + | switchStatement # SwitchStmt + | expressionStatement # ExpressionStmt + | SEMI_COLON # EmptyStmt ; block : '{' statements '}' ; @@ -118,29 +118,28 @@ returnStatement : RETURN expression? ; switchStatement : SWITCH '(' expression ')' '{' (switchLabel ':' statements )+ '}' ; switchLabel - : CASE constantExpression - | DEFAULT + : CASE constantExpression # Case + | DEFAULT # Default ; expressionStatement : expression SEMI_COLON ; expression - : constantExpression - | functionCall - | identifierExpression - | '(' expression ')' - | unaryOp expression - | identifierExpression binaryAssignOp expression - | expression binaryOp expression - | expression postUnaryOp + : unaryOp expression # UnaryExpr + | expression binaryOp expression # BinaryExpr + | expression postUnaryOp # PostUnaryExpr + | ID binaryAssignOp expression # AssignExpr + | expression '?' expression ':' expression # TernaryExpr + | functionCall # FunctionCallExpr + | constantExpression # ConstantExpr + | ID # IdExpr + | '(' expression ')' # WrappedExpr ; constantExpression : NUMBER ; functionCall : ID '(' (expression ( ',' expression )*)? ')' ; -identifierExpression : ID ; - unaryOp : MINUS | EXCLAMATION_MARK From 1ba02c54b7030d27ca64b9e3ae4fbb42977d7287 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Fri, 18 Oct 2019 22:24:56 -0700 Subject: [PATCH 352/366] Completely rewrite the expression parser in ANTLR. --- .../com/sk89q/worldedit/antlr/Expression.g4 | 207 +++--- .../java/com/sk89q/worldedit/EditSession.java | 19 +- .../function/mask/ExpressionMask.java | 2 +- .../function/mask/ExpressionMask2D.java | 2 +- .../{runtime => }/BreakException.java | 9 +- .../expression/EvaluatingVisitor.java | 625 ++++++++++++++++++ .../{runtime => }/EvaluationException.java | 2 +- .../internal/expression/Expression.java | 131 ++-- .../{runtime => }/ExpressionEnvironment.java | 2 +- .../expression/ExpressionException.java | 2 +- .../internal/expression/ExpressionHelper.java | 149 +++++ .../ExpressionTimeoutException.java | 2 +- .../expression/ExpressionValidator.java | 70 ++ .../internal/expression/Functions.java | 337 ++++++++++ ...mberToken.java => LexerErrorListener.java} | 27 +- .../{lexer => }/LexerException.java | 4 +- .../internal/expression/LocalSlot.java | 69 ++ ...torToken.java => ParserErrorListener.java} | 27 +- .../{parser => }/ParserException.java | 4 +- .../internal/expression/SlotTable.java | 64 ++ .../internal/expression/lexer/Lexer.java | 240 ------- .../lexer/tokens/CharacterToken.java | 44 -- .../lexer/tokens/IdentifierToken.java | 44 -- .../expression/lexer/tokens/KeywordToken.java | 44 -- .../expression/lexer/tokens/Token.java | 40 -- .../internal/expression/parser/Parser.java | 464 ------------- .../expression/parser/ParserProcessors.java | 352 ---------- .../expression/parser/PseudoToken.java | 43 -- .../expression/parser/UnaryOperator.java | 50 -- .../expression/parser/UnboundVariable.java | 80 --- .../internal/expression/runtime/Break.java | 50 -- .../expression/runtime/Conditional.java | 93 --- .../internal/expression/runtime/Constant.java | 49 -- .../internal/expression/runtime/For.java | 107 --- .../internal/expression/runtime/Function.java | 123 ---- .../expression/runtime/Functions.java | 487 -------------- .../internal/expression/runtime/LValue.java | 38 -- .../expression/runtime/LValueFunction.java | 77 --- .../internal/expression/runtime/Node.java | 54 -- .../expression/runtime/Operators.java | 228 ------- .../internal/expression/runtime/RValue.java | 37 -- .../internal/expression/runtime/Return.java | 60 -- .../expression/runtime/ReturnException.java | 41 -- .../internal/expression/runtime/Sequence.java | 109 --- .../expression/runtime/SimpleFor.java | 104 --- .../internal/expression/runtime/Switch.java | 206 ------ .../internal/expression/runtime/Variable.java | 67 -- .../internal/expression/runtime/While.java | 133 ---- .../shape/WorldEditExpressionEnvironment.java | 2 +- .../internal/expression/ExpressionTest.java | 113 ++-- 50 files changed, 1597 insertions(+), 3736 deletions(-) rename worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/{runtime => }/BreakException.java (78%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/EvaluatingVisitor.java rename worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/{runtime => }/EvaluationException.java (96%) rename worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/{runtime => }/ExpressionEnvironment.java (95%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java rename worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/{runtime => }/ExpressionTimeoutException.java (94%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionValidator.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java rename worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/{lexer/tokens/NumberToken.java => LexerErrorListener.java} (65%) rename worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/{lexer => }/LexerException.java (92%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java rename worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/{lexer/tokens/OperatorToken.java => ParserErrorListener.java} (65%) rename worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/{parser => }/ParserException.java (92%) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/Lexer.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/CharacterToken.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/IdentifierToken.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/KeywordToken.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/Token.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/Parser.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserProcessors.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/PseudoToken.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnaryOperator.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnboundVariable.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Break.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Conditional.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Constant.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Function.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Functions.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValue.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValueFunction.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Node.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Operators.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/RValue.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Return.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ReturnException.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Sequence.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/SimpleFor.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Switch.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Variable.java delete mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/While.java diff --git a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 index b244f2c64..c98965af6 100644 --- a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 +++ b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 @@ -79,107 +79,158 @@ allStatements : statements EOF ; statements : statement+ ; statement - : block # BlockStmt - | ifStatement # IfStmt - | whileStatement # WhileStmt - | doStatement # DoStmt - | forStatement # ForStmt - | breakStatement # BreakStmt - | continueStatement # ContinueStmt - | returnStatement # ReturnStmt - | switchStatement # SwitchStmt - | expressionStatement # ExpressionStmt - | SEMI_COLON # EmptyStmt + : ( block + | ifStatement + | whileStatement + | doStatement + | forStatement + | simpleForStatement + | breakStatement + | continueStatement + | returnStatement + | switchStatement + | expressionStatement + | emptyStatement + ) SEMI_COLON? ; block : '{' statements '}' ; -ifStatement : IF '(' expression ')' statement ( ELSE statement ) ; +ifStatement : IF '(' condition=expression ')' trueBranch=statement ( ELSE falseBranch=statement )? ; -whileStatement : WHILE '(' expression ')' statement ; +whileStatement : WHILE '(' condition=expression ')' body=statement ; -doStatement : DO statement WHILE '(' expression ')' SEMI_COLON ; +doStatement : DO body=statement WHILE '(' condition=expression ')' ; +// C-Style for loop forStatement - : FOR '(' - // C-style for loop - ( expression ';' expression ';' expression - // Range for loop - | ID ASSIGN ID ',' ID - ) - ')' statement ; + : FOR '(' init=expression ';' condition=expression ';' update=expression ')' body=statement ; + +// Range for loop +simpleForStatement + : FOR '(' counter=ID ASSIGN first=expression ',' last=expression ')' body=statement ; breakStatement : BREAK ; continueStatement : CONTINUE ; -returnStatement : RETURN expression? ; +returnStatement : RETURN value=expression? ; -switchStatement : SWITCH '(' expression ')' '{' (switchLabel ':' statements )+ '}' ; +switchStatement : SWITCH '(' target=expression ')' '{' (labels+=switchLabel ':' bodies+=statements )+ '}' ; switchLabel - : CASE constantExpression # Case + : CASE constant=constantExpression # Case | DEFAULT # Default ; -expressionStatement : expression SEMI_COLON ; +expressionStatement : expression ; -expression - : unaryOp expression # UnaryExpr - | expression binaryOp expression # BinaryExpr - | expression postUnaryOp # PostUnaryExpr - | ID binaryAssignOp expression # AssignExpr - | expression '?' expression ':' expression # TernaryExpr - | functionCall # FunctionCallExpr +emptyStatement: SEMI_COLON ; + +expression : assignmentExpression ; + +assignmentExpression + : conditionalExpression + | assignment + ; + +assignment + : target=ID assignmentOperator source=expression + ; + +assignmentOperator + : ASSIGN + | POWER_ASSIGN + | TIMES_ASSIGN + | DIVIDE_ASSIGN + | MODULO_ASSIGN + | PLUS_ASSIGN + | MINUS_ASSIGN + ; + +conditionalExpression + : conditionalOrExpression # CEFallthrough + | condition=conditionalOrExpression QUESTION_MARK + trueBranch=expression COLON falseBranch=conditionalExpression # TernaryExpr + ; + +conditionalOrExpression + : conditionalAndExpression # COFallthrough + | left=conditionalOrExpression OR_SC right=conditionalAndExpression # ConditionalOrExpr + ; + +conditionalAndExpression + : equalityExpression # CAFallthrough + | left=conditionalAndExpression AND_SC right=equalityExpression # ConditionalAndExpr + ; + +equalityExpression + : relationalExpression # EqFallthrough + | left=equalityExpression + op= + ( EQUAL + | NOT_EQUAL + | NEAR + ) right=relationalExpression # EqualityExpr + ; + +relationalExpression + : shiftExpression # ReFallthrough + | left=relationalExpression + op= + ( LESS_THAN + | GREATER_THAN + | LESS_THAN_OR_EQUAL + | GREATER_THAN_OR_EQUAL + ) right=shiftExpression # RelationalExpr + ; + +shiftExpression + : additiveExpression # ShFallthrough + | left=shiftExpression op=( LEFT_SHIFT | RIGHT_SHIFT ) right=additiveExpression # ShiftExpr + ; + +additiveExpression + : multiplicativeExpression # AdFallthrough + | left=additiveExpression op=( PLUS | MINUS ) right=multiplicativeExpression # AddExpr + ; + +multiplicativeExpression + : powerExpression # MuFallthrough + | left=multiplicativeExpression + op= + ( TIMES + | DIVIDE + | MODULO + ) right=powerExpression # MultiplicativeExpr + ; + +powerExpression + : unaryExpression # PwFallthrough + | left=powerExpression POWER right=unaryExpression # PowerExpr + ; + +unaryExpression + : op=( INCREMENT | DECREMENT ) target=ID # PreCrementExpr + | op=( PLUS | MINUS ) expr=unaryExpression # PlusMinusExpr + | postfixExpression # UaFallthrough + | COMPLEMENT expr=unaryExpression # ComplementExpr + | EXCLAMATION_MARK expr=unaryExpression # NotExpr + ; + +postfixExpression + : unprioritizedExpression # PoFallthrough + | target=ID op=( INCREMENT | DECREMENT) # PostCrementExpr + | expr=postfixExpression op=EXCLAMATION_MARK # PostfixExpr + ; + +unprioritizedExpression + : functionCall # FunctionCallExpr | constantExpression # ConstantExpr - | ID # IdExpr + | source=ID # IdExpr | '(' expression ')' # WrappedExpr ; constantExpression : NUMBER ; -functionCall : ID '(' (expression ( ',' expression )*)? ')' ; - -unaryOp - : MINUS - | EXCLAMATION_MARK - | COMPLEMENT - | INCREMENT - | DECREMENT - ; - -postUnaryOp - : INCREMENT - | DECREMENT - | EXCLAMATION_MARK - ; - -binaryOp - : POWER - | TIMES - | DIVIDE - | MODULO - | PLUS - | MINUS - | LEFT_SHIFT - | RIGHT_SHIFT - | LESS_THAN - | GREATER_THAN - | LESS_THAN_OR_EQUAL - | GREATER_THAN_OR_EQUAL - | EQUAL - | NOT_EQUAL - | NEAR - | AND_SC - | OR_SC - ; - -binaryAssignOp - : ASSIGN - | PLUS_ASSIGN - | MINUS_ASSIGN - | TIMES_ASSIGN - | DIVIDE_ASSIGN - | MODULO_ASSIGN - | POWER_ASSIGN - ; +functionCall : name=ID '(' (args+=expression ( ',' args+=expression )*)? ')' ; 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 f195ed7de..c64e6ca72 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -80,8 +80,8 @@ import com.sk89q.worldedit.history.changeset.BlockOptimizedHistory; import com.sk89q.worldedit.history.changeset.ChangeSet; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; -import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException; -import com.sk89q.worldedit.internal.expression.runtime.RValue; +import com.sk89q.worldedit.internal.expression.ExpressionTimeoutException; +import com.sk89q.worldedit.internal.expression.LocalSlot.Variable; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.MathUtils; @@ -1989,8 +1989,10 @@ public class EditSession implements Extent, AutoCloseable { final Expression expression = Expression.compile(expressionString, "x", "y", "z", "type", "data"); expression.optimize(); - final RValue typeVariable = expression.getVariable("type", false); - final RValue dataVariable = expression.getVariable("data", false); + final Variable typeVariable = expression.getSlots().getVariable("type") + .orElseThrow(IllegalStateException::new); + final Variable dataVariable = expression.getSlots().getVariable("data") + .orElseThrow(IllegalStateException::new); final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero); expression.setEnvironment(environment); @@ -2052,9 +2054,12 @@ public class EditSession implements Extent, AutoCloseable { final Expression expression = Expression.compile(expressionString, "x", "y", "z"); expression.optimize(); - final RValue x = expression.getVariable("x", false); - final RValue y = expression.getVariable("y", false); - final RValue z = expression.getVariable("z", false); + final Variable x = expression.getSlots().getVariable("x") + .orElseThrow(IllegalStateException::new); + final Variable y = expression.getSlots().getVariable("y") + .orElseThrow(IllegalStateException::new); + final Variable z = expression.getSlots().getVariable("z") + .orElseThrow(IllegalStateException::new); final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero); expression.setEnvironment(environment); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java index eba02d0a7..e9508bcee 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask.java @@ -23,7 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; -import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; +import com.sk89q.worldedit.internal.expression.EvaluationException; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java index a50c5e375..4ce7c1709 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/ExpressionMask2D.java @@ -23,7 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.ExpressionException; -import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; +import com.sk89q.worldedit.internal.expression.EvaluationException; import com.sk89q.worldedit.math.BlockVector2; import javax.annotation.Nullable; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/BreakException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/BreakException.java similarity index 78% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/BreakException.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/BreakException.java index a3d384117..635c6d6ea 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/BreakException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/BreakException.java @@ -17,18 +17,19 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.runtime; +package com.sk89q.worldedit.internal.expression; /** * Thrown when a break or continue is encountered. * Loop constructs catch this exception. */ -public class BreakException extends EvaluationException { +public class BreakException extends RuntimeException { - final boolean doContinue; + public final boolean doContinue; public BreakException(boolean doContinue) { - super(-1, doContinue ? "'continue' encountered outside a loop" : "'break' encountered outside a loop"); + super(doContinue ? "'continue' encountered outside a loop" : "'break' encountered outside a loop", + null, true, false); this.doContinue = doContinue; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/EvaluatingVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/EvaluatingVisitor.java new file mode 100644 index 000000000..bd282e9e1 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/EvaluatingVisitor.java @@ -0,0 +1,625 @@ +/* + * 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.internal.expression; + +import com.google.common.base.Throwables; +import com.google.common.collect.SetMultimap; +import com.sk89q.worldedit.antlr.ExpressionBaseVisitor; +import com.sk89q.worldedit.antlr.ExpressionParser; +import it.unimi.dsi.fastutil.doubles.Double2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.doubles.Double2ObjectMap; +import it.unimi.dsi.fastutil.doubles.Double2ObjectMaps; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.RuleNode; +import org.antlr.v4.runtime.tree.TerminalNode; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.Optional; +import java.util.function.DoubleBinaryOperator; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static com.sk89q.worldedit.antlr.ExpressionLexer.ASSIGN; +import static com.sk89q.worldedit.antlr.ExpressionLexer.DIVIDE; +import static com.sk89q.worldedit.antlr.ExpressionLexer.DIVIDE_ASSIGN; +import static com.sk89q.worldedit.antlr.ExpressionLexer.EQUAL; +import static com.sk89q.worldedit.antlr.ExpressionLexer.EXCLAMATION_MARK; +import static com.sk89q.worldedit.antlr.ExpressionLexer.GREATER_THAN; +import static com.sk89q.worldedit.antlr.ExpressionLexer.GREATER_THAN_OR_EQUAL; +import static com.sk89q.worldedit.antlr.ExpressionLexer.INCREMENT; +import static com.sk89q.worldedit.antlr.ExpressionLexer.LEFT_SHIFT; +import static com.sk89q.worldedit.antlr.ExpressionLexer.LESS_THAN; +import static com.sk89q.worldedit.antlr.ExpressionLexer.LESS_THAN_OR_EQUAL; +import static com.sk89q.worldedit.antlr.ExpressionLexer.MINUS; +import static com.sk89q.worldedit.antlr.ExpressionLexer.MINUS_ASSIGN; +import static com.sk89q.worldedit.antlr.ExpressionLexer.MODULO; +import static com.sk89q.worldedit.antlr.ExpressionLexer.MODULO_ASSIGN; +import static com.sk89q.worldedit.antlr.ExpressionLexer.NEAR; +import static com.sk89q.worldedit.antlr.ExpressionLexer.NOT_EQUAL; +import static com.sk89q.worldedit.antlr.ExpressionLexer.PLUS; +import static com.sk89q.worldedit.antlr.ExpressionLexer.PLUS_ASSIGN; +import static com.sk89q.worldedit.antlr.ExpressionLexer.POWER_ASSIGN; +import static com.sk89q.worldedit.antlr.ExpressionLexer.RIGHT_SHIFT; +import static com.sk89q.worldedit.antlr.ExpressionLexer.TIMES; +import static com.sk89q.worldedit.antlr.ExpressionLexer.TIMES_ASSIGN; +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.WRAPPED_CONSTANT; +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.check; +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.checkIterations; +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.checkTimeout; +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.evalException; +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.getArgumentHandleName; +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.resolveFunction; + +class EvaluatingVisitor extends ExpressionBaseVisitor { + + private final SlotTable slots; + private final SetMultimap functions; + + EvaluatingVisitor(SlotTable slots, + SetMultimap functions) { + this.slots = slots; + this.functions = functions; + } + + private LocalSlot.Variable initVariable(String name, ParserRuleContext ctx) { + return slots.initVariable(name) + .orElseThrow(() -> evalException(ctx, "Cannot overwrite non-variable '" + name + "'")); + } + + private Supplier varNotInitException(String name, ParserRuleContext ctx) { + return () -> evalException(ctx, "'" + name + "' is not initialized yet"); + } + + private LocalSlot.Variable getVariable(String name, ParserRuleContext ctx) { + LocalSlot slot = slots.getSlot(name) + .orElseThrow(varNotInitException(name, ctx)); + check(slot instanceof LocalSlot.Variable, ctx, "'" + name + "' is not a variable"); + return (LocalSlot.Variable) slot; + } + + private double getSlotValue(String name, ParserRuleContext ctx) { + return slots.getSlotValue(name) + .orElseThrow(varNotInitException(name, ctx)); + } + + private Token extractToken(ParserRuleContext ctx) { + List children = ctx.children.stream() + .filter(TerminalNode.class::isInstance) + .map(TerminalNode.class::cast) + .collect(Collectors.toList()); + check(children.size() == 1, ctx, "Expected exactly one token, got " + children.size()); + return children.get(0).getSymbol(); + } + + private Double evaluate(ParserRuleContext ctx) { + return ctx.accept(this); + } + + private double evaluateForValue(ParserRuleContext ctx) { + Double result = evaluate(ctx); + check(result != null, ctx, "Invalid expression for a value"); + return result; + } + + private boolean evaluateBoolean(ParserRuleContext boolExpression) { + Double bool = evaluate(boolExpression); + check(bool != null, boolExpression, "Invalid expression for boolean"); + return doubleToBool(bool); + } + + private boolean doubleToBool(double bool) { + return bool > 0; + } + + private double boolToDouble(boolean bool) { + return bool ? 1 : 0; + } + + private Double evaluateConditional(ParserRuleContext condition, + ParserRuleContext trueBranch, + ParserRuleContext falseBranch) { + ParserRuleContext ctx = evaluateBoolean(condition) ? trueBranch : falseBranch; + return ctx == null ? null : evaluate(ctx); + } + + @Override + public Double visitIfStatement(ExpressionParser.IfStatementContext ctx) { + return evaluateConditional(ctx.condition, ctx.trueBranch, ctx.falseBranch); + } + + @Override + public Double visitTernaryExpr(ExpressionParser.TernaryExprContext ctx) { + return evaluateConditional(ctx.condition, ctx.trueBranch, ctx.falseBranch); + } + + @Override + public Double visitWhileStatement(ExpressionParser.WhileStatementContext ctx) { + Double result = defaultResult(); + int iterations = 0; + while (evaluateBoolean(ctx.condition)) { + checkIterations(iterations, ctx.body); + checkTimeout(); + iterations++; + try { + result = evaluate(ctx.body); + } catch (BreakException ex) { + if (!ex.doContinue) { + break; + } + } + } + return result; + } + + @Override + public Double visitDoStatement(ExpressionParser.DoStatementContext ctx) { + Double result = defaultResult(); + int iterations = 0; + do { + checkIterations(iterations, ctx.body); + checkTimeout(); + iterations++; + try { + result = evaluate(ctx.body); + } catch (BreakException ex) { + if (!ex.doContinue) { + break; + } + } + } while (evaluateBoolean(ctx.condition)); + return result; + } + + @Override + public Double visitForStatement(ExpressionParser.ForStatementContext ctx) { + Double result = defaultResult(); + int iterations = 0; + evaluate(ctx.init); + while (evaluateBoolean(ctx.condition)) { + checkIterations(iterations, ctx.body); + checkTimeout(); + iterations++; + try { + result = evaluate(ctx.body); + } catch (BreakException ex) { + if (!ex.doContinue) { + break; + } + } + evaluate(ctx.update); + } + return result; + } + + @Override + public Double visitSimpleForStatement(ExpressionParser.SimpleForStatementContext ctx) { + Double result = defaultResult(); + int iterations = 0; + double first = evaluateForValue(ctx.first); + double last = evaluateForValue(ctx.last); + String counter = ctx.counter.getText(); + LocalSlot.Variable variable = initVariable(counter, ctx); + for (double i = first; i <= last; i++) { + checkIterations(iterations, ctx.body); + checkTimeout(); + iterations++; + variable.setValue(i); + try { + result = evaluate(ctx.body); + } catch (BreakException ex) { + if (!ex.doContinue) { + break; + } + } + } + return result; + } + + @Override + public Double visitBreakStatement(ExpressionParser.BreakStatementContext ctx) { + throw new BreakException(false); + } + + @Override + public Double visitContinueStatement(ExpressionParser.ContinueStatementContext ctx) { + throw new BreakException(true); + } + + @Override + public Double visitReturnStatement(ExpressionParser.ReturnStatementContext ctx) { + if (ctx.value != null) { + return evaluate(ctx.value); + } + return null; + } + + @Override + public Double visitSwitchStatement(ExpressionParser.SwitchStatementContext ctx) { + Double2ObjectMap cases = new Double2ObjectLinkedOpenHashMap<>(ctx.labels.size()); + ParserRuleContext defaultCase = null; + for (int i = 0; i < ctx.labels.size(); i++) { + ExpressionParser.SwitchLabelContext label = ctx.labels.get(i); + ExpressionParser.StatementsContext body = ctx.bodies.get(i); + if (label instanceof ExpressionParser.CaseContext) { + ExpressionParser.CaseContext caseContext = (ExpressionParser.CaseContext) label; + double key = evaluateForValue(caseContext.constant); + check(!cases.containsKey(key), body, "Duplicate cases detected."); + cases.put(key, body); + } else { + check(defaultCase == null, body, "Duplicate default cases detected."); + defaultCase = body; + } + } + double value = evaluateForValue(ctx.target); + boolean matched = false; + Double evaluated = null; + boolean falling = false; + for (Double2ObjectMap.Entry entry : Double2ObjectMaps.fastIterable(cases)) { + if (falling || entry.getDoubleKey() == value) { + matched = true; + try { + evaluated = evaluate(entry.getValue()); + falling = true; + } catch (BreakException brk) { + check(!brk.doContinue, entry.getValue(), "Cannot continue in a switch"); + falling = false; + break; + } + } + } + // This if is like the one in the loop, default's "case" is `!matched` & present + if ((falling || !matched) && defaultCase != null) { + try { + evaluated = evaluate(defaultCase); + } catch (BreakException brk) { + check(!brk.doContinue, defaultCase, "Cannot continue in a switch"); + } + } + return evaluated; + } + + @Override + public Double visitExpressionStatement(ExpressionParser.ExpressionStatementContext ctx) { + return evaluate(ctx.expression()); + } + + @Override + public Double visitPostCrementExpr(ExpressionParser.PostCrementExprContext ctx) { + String target = ctx.target.getText(); + LocalSlot.Variable variable = getVariable(target, ctx); + double value = variable.getValue(); + if (ctx.op.getType() == INCREMENT) { + value++; + } else { + value--; + } + variable.setValue(value); + return value; + } + + @Override + public Double visitPreCrementExpr(ExpressionParser.PreCrementExprContext ctx) { + String target = ctx.target.getText(); + LocalSlot.Variable variable = getVariable(target, ctx); + double value = variable.getValue(); + double result = value; + if (ctx.op.getType() == INCREMENT) { + value++; + } else { + value--; + } + variable.setValue(value); + return result; + } + + @Override + public Double visitPlusMinusExpr(ExpressionParser.PlusMinusExprContext ctx) { + double value = evaluateForValue(ctx.expr); + switch (ctx.op.getType()) { + case PLUS: + return +value; + case MINUS: + return -value; + } + throw evalException(ctx, "Invalid text for plus/minus expr: " + ctx.op.getText()); + } + + @Override + public Double visitNotExpr(ExpressionParser.NotExprContext ctx) { + return boolToDouble(!evaluateBoolean(ctx.expr)); + } + + @Override + public Double visitComplementExpr(ExpressionParser.ComplementExprContext ctx) { + return (double) ~(long) evaluateForValue(ctx.expr); + } + + @Override + public Double visitConditionalAndExpr(ExpressionParser.ConditionalAndExprContext ctx) { + if (!evaluateBoolean(ctx.left)) { + return boolToDouble(false); + } + return evaluateForValue(ctx.right); + } + + @Override + public Double visitConditionalOrExpr(ExpressionParser.ConditionalOrExprContext ctx) { + double left = evaluateForValue(ctx.left); + if (doubleToBool(left)) { + return left; + } + return evaluateForValue(ctx.right); + } + + private double evaluateBinary(ParserRuleContext left, + ParserRuleContext right, + DoubleBinaryOperator op) { + return op.applyAsDouble(evaluateForValue(left), evaluateForValue(right)); + } + + @Override + public Double visitPowerExpr(ExpressionParser.PowerExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, Math::pow); + } + + @Override + public Double visitMultiplicativeExpr(ExpressionParser.MultiplicativeExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, (l, r) -> { + switch (ctx.op.getType()) { + case TIMES: + return l * r; + case DIVIDE: + return l / r; + case MODULO: + return l % r; + } + throw evalException(ctx, "Invalid text for multiplicative expr: " + ctx.op.getText()); + }); + } + + @Override + public Double visitAddExpr(ExpressionParser.AddExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, (l, r) -> { + switch (ctx.op.getType()) { + case PLUS: + return l + r; + case MINUS: + return l - r; + } + throw evalException(ctx, "Invalid text for additive expr: " + ctx.op.getText()); + }); + } + + @Override + public Double visitShiftExpr(ExpressionParser.ShiftExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, (l, r) -> { + switch (ctx.op.getType()) { + case LEFT_SHIFT: + return (double) ((long) l << (long) r); + case RIGHT_SHIFT: + return (double) ((long) l >> (long) r); + } + throw evalException(ctx, "Invalid text for shift expr: " + ctx.op.getText()); + }); + } + + @Override + public Double visitRelationalExpr(ExpressionParser.RelationalExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, (l, r) -> { + switch (ctx.op.getType()) { + case LESS_THAN: + return boolToDouble(l < r); + case LESS_THAN_OR_EQUAL: + return boolToDouble(l <= r); + case GREATER_THAN: + return boolToDouble(l > r); + case GREATER_THAN_OR_EQUAL: + return boolToDouble(l >= r); + } + throw evalException(ctx, "Invalid text for relational expr: " + ctx.op.getText()); + }); + } + + @Override + public Double visitEqualityExpr(ExpressionParser.EqualityExprContext ctx) { + return evaluateBinary(ctx.left, ctx.right, (l, r) -> { + switch (ctx.op.getType()) { + case EQUAL: + return boolToDouble(l == r); + case NOT_EQUAL: + return boolToDouble(l != r); + case NEAR: + return boolToDouble(almostEqual2sComplement(l, r, 450359963L)); + case GREATER_THAN_OR_EQUAL: + return boolToDouble(l >= r); + } + throw evalException(ctx, "Invalid text for equality expr: " + ctx.op.getText()); + }); + } + + // Usable AlmostEqual function, based on http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm + private static boolean almostEqual2sComplement(double a, double b, long maxUlps) { + // Make sure maxUlps is non-negative and small enough that the + // default NAN won't compare as equal to anything. + //assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); // this is for floats, not doubles + + long aLong = Double.doubleToRawLongBits(a); + // Make aLong lexicographically ordered as a twos-complement long + if (aLong < 0) aLong = 0x8000000000000000L - aLong; + + long bLong = Double.doubleToRawLongBits(b); + // Make bLong lexicographically ordered as a twos-complement long + if (bLong < 0) bLong = 0x8000000000000000L - bLong; + + final long longDiff = Math.abs(aLong - bLong); + return longDiff <= maxUlps; + } + + @Override + public Double visitPostfixExpr(ExpressionParser.PostfixExprContext ctx) { + double value = evaluateForValue(ctx.expr); + if (ctx.op.getType() == EXCLAMATION_MARK) { + return factorial(value); + } + throw evalException(ctx, + "Invalid text for post-unary expr: " + ctx.op.getText()); + } + + private static final double[] factorials = new double[171]; + + static { + factorials[0] = 1; + for (int i = 1; i < factorials.length; ++i) { + factorials[i] = factorials[i - 1] * i; + } + } + + private static double factorial(double x) throws EvaluationException { + final int n = (int) x; + + if (n < 0) { + return 0; + } + + if (n >= factorials.length) { + return Double.POSITIVE_INFINITY; + } + + return factorials[n]; + } + + @Override + public Double visitAssignment(ExpressionParser.AssignmentContext ctx) { + int type = extractToken(ctx.assignmentOperator()).getType(); + String target = ctx.target.getText(); + double value; + double arg = evaluateForValue(ctx.expression()); + LocalSlot.Variable variable; + if (type == ASSIGN) { + variable = initVariable(target, ctx); + value = arg; + } else { + variable = getVariable(target, ctx); + value = variable.getValue(); + switch (type) { + case POWER_ASSIGN: + value = Math.pow(value, arg); + break; + case TIMES_ASSIGN: + value *= arg; + break; + case DIVIDE_ASSIGN: + value /= arg; + break; + case MODULO_ASSIGN: + value %= arg; + break; + case PLUS_ASSIGN: + value += arg; + break; + case MINUS_ASSIGN: + value -= arg; + break; + default: + throw evalException(ctx, "Invalid text for assign expr: " + + ctx.assignmentOperator().getText()); + } + } + variable.setValue(value); + return value; + } + + @Override + public Double visitFunctionCall(ExpressionParser.FunctionCallContext ctx) { + MethodHandle handle = resolveFunction(functions, ctx); + String fnName = ctx.name.getText(); + Object[] arguments = new Object[ctx.args.size()]; + for (int i = 0; i < arguments.length; i++) { + ExpressionParser.ExpressionContext arg = ctx.args.get(i); + Object transformed = getArgument(fnName, handle.type(), i, arg); + arguments[i] = transformed; + } + try { + // Some methods return other Numbers + Number number = (Number) handle.invokeWithArguments(arguments); + return number == null ? null : number.doubleValue(); + } catch (Throwable throwable) { + Throwables.throwIfUnchecked(throwable); + throw new RuntimeException(throwable); + } + } + + private Object getArgument(String fnName, MethodType type, int i, ParserRuleContext arg) { + // Pass variable handle in for modification? + String handleName = getArgumentHandleName(fnName, type, i, arg); + if (handleName == null) { + return evaluateForValue(arg); + } + if (handleName.equals(WRAPPED_CONSTANT)) { + return new LocalSlot.Constant(evaluateForValue(arg)); + } + return getVariable(handleName, arg); + } + + @Override + public Double visitConstantExpression(ExpressionParser.ConstantExpressionContext ctx) { + try { + return Double.parseDouble(ctx.getText()); + } catch (NumberFormatException e) { + // Rare, but might happen, e.g. if too many digits + throw evalException(ctx, "Invalid constant: " + e.getMessage()); + } + } + + @Override + public Double visitIdExpr(ExpressionParser.IdExprContext ctx) { + String source = ctx.source.getText(); + return getSlotValue(source, ctx); + } + + @Override + public Double visitChildren(RuleNode node) { + Double result = defaultResult(); + int n = node.getChildCount(); + for (int i = 0; i < n; i++) { + ParseTree c = node.getChild(i); + if (c instanceof TerminalNode && ((TerminalNode) c).getSymbol().getType() == Token.EOF) { + break; + } + + Double childResult = c.accept(this); + if (c instanceof ExpressionParser.ReturnStatementContext) { + return childResult; + } + result = aggregateResult(result, childResult); + } + + return result; + } + + @Override + protected Double aggregateResult(Double aggregate, Double nextResult) { + return Optional.ofNullable(nextResult).orElse(aggregate); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/EvaluationException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/EvaluationException.java similarity index 96% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/EvaluationException.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/EvaluationException.java index fc34a0ffa..c9042d7ca 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/EvaluationException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/EvaluationException.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.runtime; +package com.sk89q.worldedit.internal.expression; import com.sk89q.worldedit.internal.expression.ExpressionException; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java index 0e82a4750..9bca48e12 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java @@ -19,24 +19,23 @@ package com.sk89q.worldedit.internal.expression; +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.SetMultimap; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.internal.expression.lexer.Lexer; -import com.sk89q.worldedit.internal.expression.lexer.tokens.Token; -import com.sk89q.worldedit.internal.expression.parser.Parser; -import com.sk89q.worldedit.internal.expression.runtime.Constant; -import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; -import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; -import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException; -import com.sk89q.worldedit.internal.expression.runtime.Functions; -import com.sk89q.worldedit.internal.expression.runtime.RValue; -import com.sk89q.worldedit.internal.expression.runtime.ReturnException; -import com.sk89q.worldedit.internal.expression.runtime.Variable; +import com.sk89q.worldedit.antlr.ExpressionLexer; +import com.sk89q.worldedit.antlr.ExpressionParser; import com.sk89q.worldedit.session.request.Request; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.misc.ParseCancellationException; +import org.antlr.v4.runtime.tree.ParseTreeWalker; -import java.util.HashMap; +import java.lang.invoke.MethodHandle; import java.util.List; -import java.util.Map; +import java.util.Objects; import java.util.Stack; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -68,13 +67,8 @@ import java.util.concurrent.TimeoutException; * If you wish to run the equation multiple times, you can then optimize it, * by calling {@link #optimize()}. You can then run the equation as many times * as you want by calling {@link #evaluate(double...)}. You do not need to - * pass values for all variables specified while compiling. - * To query variables after evaluation, you can use - * {@link #getVariable(String, boolean)}. To get a value out of these, use - * {@link Variable#getValue()}.

    - * - *

    Variables are also supported and can be set either by passing values - * to {@link #evaluate(double...)}.

    + * pass values for all slots specified while compiling. + * To query slots after evaluation, you can use the {@linkplain #getSlots() slot table}. */ public class Expression { @@ -85,10 +79,10 @@ public class Expression { .setNameFormat("worldedit-expression-eval-%d") .build()); - private final Map variables = new HashMap<>(); - private final String[] variableNames; - private RValue root; - private final Functions functions = new Functions(); + private final SlotTable slots = new SlotTable(); + private final List providedSlots; + private ExpressionParser.AllStatementsContext root; + private final SetMultimap functions = Functions.getFunctionMap(); private ExpressionEnvironment environment; public static Expression compile(String expression, String... variableNames) throws ExpressionException { @@ -96,25 +90,33 @@ public class Expression { } private Expression(String expression, String... variableNames) throws ExpressionException { - this(Lexer.tokenize(expression), variableNames); - } - - private Expression(List tokens, String... variableNames) throws ExpressionException { - this.variableNames = variableNames; - - variables.put("e", new Constant(-1, Math.E)); - variables.put("pi", new Constant(-1, Math.PI)); - variables.put("true", new Constant(-1, 1)); - variables.put("false", new Constant(-1, 0)); + slots.putSlot("e", new LocalSlot.Constant(Math.E)); + slots.putSlot("pi", new LocalSlot.Constant(Math.PI)); + slots.putSlot("true", new LocalSlot.Constant(1)); + slots.putSlot("false", new LocalSlot.Constant(0)); for (String variableName : variableNames) { - if (variables.containsKey(variableName)) { - throw new ExpressionException(-1, "Tried to overwrite identifier '" + variableName + "'"); - } - variables.put(variableName, new Variable(0)); + slots.initVariable(variableName) + .orElseThrow(() -> new ExpressionException(-1, + "Tried to overwrite identifier '" + variableName + "'")); } + this.providedSlots = ImmutableList.copyOf(variableNames); - root = Parser.parse(tokens, this); + CharStream cs = CharStreams.fromString(expression, ""); + ExpressionLexer lexer = new ExpressionLexer(cs); + lexer.removeErrorListeners(); + lexer.addErrorListener(new LexerErrorListener()); + CommonTokenStream tokens = new CommonTokenStream(lexer); + ExpressionParser parser = new ExpressionParser(tokens); + parser.removeErrorListeners(); + parser.addErrorListener(new ParserErrorListener()); + try { + root = parser.allStatements(); + Objects.requireNonNull(root, "Unable to parse root, but no exceptions?"); + } catch (ParseCancellationException e) { + throw new ParserException(parser.getState(), e); + } + ParseTreeWalker.DEFAULT.walk(new ExpressionValidator(slots.keySet(), functions), root); } public double evaluate(double... values) throws EvaluationException { @@ -123,23 +125,19 @@ public class Expression { public double evaluate(double[] values, int timeout) throws EvaluationException { for (int i = 0; i < values.length; ++i) { - final String variableName = variableNames[i]; - final RValue invokable = variables.get(variableName); - if (!(invokable instanceof Variable)) { - throw new EvaluationException(invokable.getPosition(), "Tried to assign constant " + variableName + "."); - } + String slotName = providedSlots.get(i); + LocalSlot.Variable slot = slots.getVariable(slotName) + .orElseThrow(() -> new EvaluationException(-1, + "Tried to assign to non-variable " + slotName + ".")); - ((Variable) invokable).value = values[i]; + slot.setValue(values[i]); } - try { - if (timeout < 0) { - return evaluateRoot(); - } - return evaluateRootTimed(timeout); - } catch (ReturnException e) { - return e.getValue(); - } // other evaluation exceptions are thrown out of this method + // evaluation exceptions are thrown out of this method + if (timeout < 0) { + return evaluateRoot(); + } + return evaluateRootTimed(timeout); } private double evaluateRootTimed(int timeout) throws EvaluationException { @@ -165,12 +163,8 @@ public class Expression { throw new ExpressionTimeoutException("Calculations exceeded time limit."); } catch (ExecutionException e) { Throwable cause = e.getCause(); - if (cause instanceof EvaluationException) { - throw (EvaluationException) cause; - } - if (cause instanceof RuntimeException) { - throw (RuntimeException) cause; - } + Throwables.throwIfInstanceOf(cause, EvaluationException.class); + Throwables.throwIfUnchecked(cause); throw new RuntimeException(cause); } } @@ -178,14 +172,14 @@ public class Expression { private Double evaluateRoot() throws EvaluationException { pushInstance(); try { - return root.getValue(); + return root.accept(new EvaluatingVisitor(slots, functions)); } finally { popInstance(); } } - public void optimize() throws EvaluationException { - root = root.optimize(); + public void optimize() { + // TODO optimizing } @Override @@ -193,13 +187,8 @@ public class Expression { return root.toString(); } - public RValue getVariable(String name, boolean create) { - RValue variable = variables.get(name); - if (variable == null && create) { - variables.put(name, variable = new Variable(0)); - } - - return variable; + public SlotTable getSlots() { + return slots; } public static Expression getInstance() { @@ -225,10 +214,6 @@ public class Expression { } } - public Functions getFunctions() { - return functions; - } - public ExpressionEnvironment getEnvironment() { return environment; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ExpressionEnvironment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java similarity index 95% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ExpressionEnvironment.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java index 1a9a57d4a..9fa11e923 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ExpressionEnvironment.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionEnvironment.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.runtime; +package com.sk89q.worldedit.internal.expression; /** * Represents a way to access blocks in a world. Has to accept non-rounded coordinates. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java index 2320ad99c..41c6f8863 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionException.java @@ -23,7 +23,7 @@ package com.sk89q.worldedit.internal.expression; * Thrown when there's a problem during any stage of the expression * compilation or evaluation. */ -public class ExpressionException extends Exception { +public class ExpressionException extends RuntimeException { private final int position; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java new file mode 100644 index 000000000..f1689f78e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionHelper.java @@ -0,0 +1,149 @@ +/* + * 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.internal.expression; + +import com.google.common.collect.SetMultimap; +import com.sk89q.worldedit.antlr.ExpressionParser; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.sk89q.worldedit.antlr.ExpressionLexer.ID; + +class ExpressionHelper { + + static void check(boolean condition, ParserRuleContext ctx, String message) { + if (!condition) { + throw evalException(ctx, message); + } + } + + static EvaluationException evalException(ParserRuleContext ctx, String message) { + return new EvaluationException( + ctx.getStart().getCharPositionInLine(), + message + ); + } + + static void checkIterations(int iterations, ParserRuleContext ctx) { + check(iterations <= 256, ctx, "Loop exceeded 256 iterations"); + } + + static void checkTimeout() { + if (Thread.interrupted()) { + throw new ExpressionTimeoutException("Calculations exceeded time limit."); + } + } + + static MethodHandle resolveFunction(SetMultimap functions, + ExpressionParser.FunctionCallContext ctx) { + String fnName = ctx.name.getText(); + Set matchingFns = functions.get(fnName); + check(!matchingFns.isEmpty(), ctx, "Unknown function '" + fnName + "'"); + for (MethodHandle function : matchingFns) { + MethodType type = function.type(); + // Validate argc if not varargs + if (!function.isVarargsCollector() && type.parameterCount() != ctx.args.size()) { + // skip non-matching function + continue; + } + for (int i = 0; i < ctx.args.size(); i++) { + ExpressionParser.ExpressionContext arg = ctx.args.get(i); + getArgumentHandleName(fnName, type, i, arg); + } + // good match! + return function; + } + // We matched no function, fail with appropriate message. + String possibleCounts = matchingFns.stream() + .map(mh -> mh.isVarargsCollector() + ? (mh.type().parameterCount() - 1) + "+" + : String.valueOf(mh.type().parameterCount())) + .collect(Collectors.joining("/")); + throw evalException(ctx, "Incorrect number of arguments for function '" + fnName + "', " + + "expected " + possibleCounts + ", " + + "got " + ctx.args.size()); + } + + // Special argument handle names + /** + * The argument should be wrapped in a {@link LocalSlot.Constant} before being passed. + */ + static final String WRAPPED_CONSTANT = ""; + + /** + * If this argument needs a handle, returns the name of the handle needed. Otherwise, returns + * {@code null}. If {@code arg} isn't a valid handle reference, throws. + */ + static String getArgumentHandleName(String fnName, MethodType type, int i, + ParserRuleContext arg) { + // Pass variable handle in for modification? + Class pType = type.parameterType(i); + Optional id = tryResolveId(arg); + if (pType == LocalSlot.Variable.class) { + // MUST be an id + check(id.isPresent(), arg, + "Function '" + fnName + "' requires a variable in parameter " + i); + return id.get(); + } else if (pType == LocalSlot.class) { + return id.orElse(WRAPPED_CONSTANT); + } + return null; + } + + private static Optional tryResolveId(ParserRuleContext arg) { + Optional wrappedExprContext = + tryAs(arg, ExpressionParser.WrappedExprContext.class); + if (wrappedExprContext.isPresent()) { + return tryResolveId(wrappedExprContext.get().expression()); + } + Token token = arg.start; + int tokenType = token.getType(); + boolean isId = arg.start == arg.stop && tokenType == ID; + return isId ? Optional.of(token.getText()) : Optional.empty(); + } + + private static Optional tryAs( + ParserRuleContext ctx, + Class rule + ) { + if (rule.isInstance(ctx)) { + return Optional.of(rule.cast(ctx)); + } + if (ctx.children.size() != 1) { + return Optional.empty(); + } + List ctxs = ctx.getRuleContexts(ParserRuleContext.class); + if (ctxs.size() != 1) { + return Optional.empty(); + } + return tryAs(ctxs.get(0), rule); + } + + private ExpressionHelper() { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ExpressionTimeoutException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionTimeoutException.java similarity index 94% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ExpressionTimeoutException.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionTimeoutException.java index ce7d55140..e0395cd7a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ExpressionTimeoutException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionTimeoutException.java @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.runtime; +package com.sk89q.worldedit.internal.expression; /** * Thrown when an evaluation exceeds the timeout time. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionValidator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionValidator.java new file mode 100644 index 000000000..c823df306 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ExpressionValidator.java @@ -0,0 +1,70 @@ +/* + * 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.internal.expression; + +import com.google.common.collect.SetMultimap; +import com.sk89q.worldedit.antlr.ExpressionBaseListener; +import com.sk89q.worldedit.antlr.ExpressionParser; + +import java.lang.invoke.MethodHandle; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.check; +import static com.sk89q.worldedit.internal.expression.ExpressionHelper.resolveFunction; + +class ExpressionValidator extends ExpressionBaseListener { + + private final Set variableNames = new HashSet<>(); + private final SetMultimap functions; + + ExpressionValidator(Collection variableNames, + SetMultimap functions) { + this.variableNames.addAll(variableNames); + this.functions = functions; + } + + private void bindVariable(String name) { + variableNames.add(name); + } + + @Override + public void enterAssignment(ExpressionParser.AssignmentContext ctx) { + bindVariable(ctx.target.getText()); + } + + @Override + public void enterSimpleForStatement(ExpressionParser.SimpleForStatementContext ctx) { + bindVariable(ctx.counter.getText()); + } + + @Override + public void enterIdExpr(ExpressionParser.IdExprContext ctx) { + String text = ctx.source.getText(); + check(variableNames.contains(text), ctx, + "Variable '" + text + "' is not bound"); + } + + @Override + public void enterFunctionCall(ExpressionParser.FunctionCallContext ctx) { + resolveFunction(functions, ctx); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java new file mode 100644 index 000000000..e97f96ade --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Functions.java @@ -0,0 +1,337 @@ +/* + * 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.internal.expression; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.SetMultimap; +import com.google.common.primitives.Doubles; +import com.sk89q.worldedit.internal.expression.LocalSlot.Variable; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.noise.PerlinNoise; +import com.sk89q.worldedit.math.noise.RidgedMultiFractalNoise; +import com.sk89q.worldedit.math.noise.VoronoiNoise; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.concurrent.ThreadLocalRandom; + +import static java.lang.invoke.MethodType.methodType; + +/** + * Contains all functions that can be used in expressions. + */ +final class Functions { + + static SetMultimap getFunctionMap() { + SetMultimap map = HashMultimap.create(); + Functions functions = new Functions(); + MethodHandles.Lookup lookup = MethodHandles.lookup(); + + try { + addMathHandles(map, lookup); + addStaticFunctionHandles(map, lookup); + functions.addInstanceFunctionHandles(map, lookup); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + + return ImmutableSetMultimap.copyOf(map); + } + + private static void addMathHandles( + SetMultimap map, + MethodHandles.Lookup lookup + ) throws NoSuchMethodException, IllegalAccessException { + // double (double) functions + for (String name : ImmutableList.of( + "sin", "cos", "tan", "asin", "acos", "atan", + "sinh", "cosh", "tanh", "sqrt", "cbrt", "abs", + "ceil", "floor", "rint", "exp", "log", "log10" + )) { + map.put(name, lookup.findStatic(Math.class, name, + methodType(double.class, double.class))); + } + // Alias ln -> log + map.put("ln", lookup.findStatic(Math.class, "log", + methodType(double.class, double.class))); + map.put("round", lookup.findStatic(Math.class, "round", + methodType(long.class, double.class))); + + map.put("atan2", lookup.findStatic(Math.class, "atan2", + methodType(double.class, double.class, double.class))); + + // Special cases: we accept varargs for these + map.put("min", lookup.findStatic(Doubles.class, "min", + methodType(double.class, double[].class)) + .asVarargsCollector(double[].class)); + map.put("max", lookup.findStatic(Doubles.class, "max", + methodType(double.class, double[].class)) + .asVarargsCollector(double[].class)); + } + + private static void addStaticFunctionHandles( + SetMultimap map, + MethodHandles.Lookup lookup + ) throws NoSuchMethodException, IllegalAccessException { + map.put("rotate", lookup.findStatic(Functions.class, "rotate", + methodType(double.class, Variable.class, Variable.class, double.class))); + map.put("swap", lookup.findStatic(Functions.class, "swap", + methodType(double.class, Variable.class, Variable.class))); + map.put("gmegabuf", lookup.findStatic(Functions.class, "gmegabuf", + methodType(double.class, double.class))); + map.put("gmegabuf", lookup.findStatic(Functions.class, "gmegabuf", + methodType(double.class, double.class, double.class))); + map.put("gclosest", lookup.findStatic(Functions.class, "gclosest", + methodType(double.class, double.class, double.class, double.class, double.class, + double.class, double.class))); + map.put("random", lookup.findStatic(Functions.class, "random", + methodType(double.class))); + map.put("randint", lookup.findStatic(Functions.class, "randint", + methodType(double.class, double.class))); + map.put("perlin", lookup.findStatic(Functions.class, "perlin", + methodType(double.class, double.class, double.class, double.class, double.class, + double.class, double.class, double.class))); + map.put("voronoi", lookup.findStatic(Functions.class, "voronoi", + methodType(double.class, double.class, double.class, double.class, double.class, + double.class))); + map.put("ridgedmulti", lookup.findStatic(Functions.class, "ridgedmulti", + methodType(double.class, double.class, double.class, double.class, double.class, + double.class, double.class))); + map.put("query", lookup.findStatic(Functions.class, "query", + methodType(double.class, double.class, double.class, double.class, LocalSlot.class, + LocalSlot.class))); + map.put("queryAbs", lookup.findStatic(Functions.class, "queryAbs", + methodType(double.class, double.class, double.class, double.class, LocalSlot.class, + LocalSlot.class))); + map.put("queryRel", lookup.findStatic(Functions.class, "queryRel", + methodType(double.class, double.class, double.class, double.class, LocalSlot.class, + LocalSlot.class))); + } + + private void addInstanceFunctionHandles( + SetMultimap map, + MethodHandles.Lookup lookup + ) throws NoSuchMethodException, IllegalAccessException { + map.put("megabuf", lookup.findSpecial(Functions.class, "megabuf", + methodType(double.class, double.class), Functions.class) + .bindTo(this)); + map.put("megabuf", lookup.findSpecial(Functions.class, "megabuf", + methodType(double.class, double.class, double.class), Functions.class) + .bindTo(this)); + map.put("closest", lookup.findSpecial(Functions.class, "closest", + methodType(double.class, double.class, double.class, double.class, double.class, + double.class, double.class), Functions.class) + .bindTo(this)); + } + + private static double rotate(Variable x, Variable y, double angle) { + final double cosF = Math.cos(angle); + final double sinF = Math.sin(angle); + + final double xOld = x.getValue(); + final double yOld = y.getValue(); + + x.setValue(xOld * cosF - yOld * sinF); + y.setValue(xOld * sinF + yOld * cosF); + + return 0.0; + } + + private static double swap(Variable x, Variable y) { + final double tmp = x.getValue(); + + x.setValue(y.getValue()); + y.setValue(tmp); + + return 0.0; + } + + + private static final Int2ObjectMap globalMegaBuffer = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap megaBuffer = new Int2ObjectOpenHashMap<>(); + + private static double[] getSubBuffer(Int2ObjectMap megabuf, int key) { + return megabuf.computeIfAbsent(key, k -> new double[1024]); + } + + private static double getBufferItem(final Int2ObjectMap megabuf, final int index) { + return getSubBuffer(megabuf, index & ~1023)[index & 1023]; + } + + private static double setBufferItem(final Int2ObjectMap megabuf, final int index, double value) { + return getSubBuffer(megabuf, index & ~1023)[index & 1023] = value; + } + + private static double gmegabuf(double index) { + return getBufferItem(globalMegaBuffer, (int) index); + } + + private static double gmegabuf(double index, double value) { + return setBufferItem(globalMegaBuffer, (int) index, value); + } + + private double megabuf(double index) { + return getBufferItem(megaBuffer, (int) index); + } + + private double megabuf(double index, double value) { + return setBufferItem(megaBuffer, (int) index, value); + } + + private double closest(double x, double y, double z, double index, double count, double stride) { + return findClosest( + megaBuffer, x, y, z, (int) index, (int) count, (int) stride + ); + } + + private static double gclosest(double x, double y, double z, double index, double count, double stride) { + return findClosest( + globalMegaBuffer, x, y, z, (int) index, (int) count, (int) stride + ); + } + + private static double findClosest(Int2ObjectMap megabuf, double x, double y, double z, int index, int count, int stride) { + int closestIndex = -1; + double minDistanceSquared = Double.MAX_VALUE; + + for (int i = 0; i < count; ++i) { + double currentX = getBufferItem(megabuf, index) - x; + double currentY = getBufferItem(megabuf, index+1) - y; + double currentZ = getBufferItem(megabuf, index+2) - z; + + double currentDistanceSquared = currentX*currentX + currentY*currentY + currentZ*currentZ; + + if (currentDistanceSquared < minDistanceSquared) { + minDistanceSquared = currentDistanceSquared; + closestIndex = index; + } + + index += stride; + } + + return closestIndex; + } + + private static double random() { + return ThreadLocalRandom.current().nextDouble(); + } + + private static double randint(double max) { + return ThreadLocalRandom.current().nextInt((int) Math.floor(max)); + } + + private static final ThreadLocal localPerlin = ThreadLocal.withInitial(PerlinNoise::new); + + private static double perlin(double seed, double x, double y, double z, + double frequency, double octaves, double persistence) { + PerlinNoise perlin = localPerlin.get(); + try { + perlin.setSeed((int) seed); + perlin.setFrequency(frequency); + perlin.setOctaveCount((int) octaves); + perlin.setPersistence(persistence); + } catch (IllegalArgumentException e) { + throw new EvaluationException(0, "Perlin noise error: " + e.getMessage()); + } + return perlin.noise(Vector3.at(x, y, z)); + } + + private static final ThreadLocal localVoronoi = ThreadLocal.withInitial(VoronoiNoise::new); + + private static double voronoi(double seed, double x, double y, double z, double frequency) { + VoronoiNoise voronoi = localVoronoi.get(); + try { + voronoi.setSeed((int) seed); + voronoi.setFrequency(frequency); + } catch (IllegalArgumentException e) { + throw new EvaluationException(0, "Voronoi error: " + e.getMessage()); + } + return voronoi.noise(Vector3.at(x, y, z)); + } + + private static final ThreadLocal localRidgedMulti = ThreadLocal.withInitial(RidgedMultiFractalNoise::new); + + private static double ridgedmulti(double seed, double x, double y, double z, + double frequency, double octaves) { + RidgedMultiFractalNoise ridgedMulti = localRidgedMulti.get(); + try { + ridgedMulti.setSeed((int) seed); + ridgedMulti.setFrequency(frequency); + ridgedMulti.setOctaveCount((int) octaves); + } catch (IllegalArgumentException e) { + throw new EvaluationException(0, "Ridged multi error: " + e.getMessage()); + } + return ridgedMulti.noise(Vector3.at(x, y, z)); + } + + private static double queryInternal(LocalSlot type, LocalSlot data, double typeId, double dataValue) { + // Compare to input values and determine return value + // -1 is a wildcard, always true + double ret = ((type.getValue() == -1 || typeId == type.getValue()) + && (data.getValue() == -1 || dataValue == data.getValue())) ? 1.0 : 0.0; + + if (type instanceof Variable) { + ((Variable) type).setValue(typeId); + } + if (data instanceof Variable) { + ((Variable) data).setValue(dataValue); + } + + return ret; + } + + private static double query(double x, double y, double z, LocalSlot type, LocalSlot data) { + final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); + + // Read values from world + final double typeId = environment.getBlockType(x, y, z); + final double dataValue = environment.getBlockData(x, y, z); + + return queryInternal(type, data, typeId, dataValue); + } + + private static double queryAbs(double x, double y, double z, LocalSlot type, LocalSlot data) { + final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); + + // Read values from world + final double typeId = environment.getBlockTypeAbs(x, y, z); + final double dataValue = environment.getBlockDataAbs(x, y, z); + + return queryInternal(type, data, typeId, dataValue); + } + + private static double queryRel(double x, double y, double z, LocalSlot type, LocalSlot data) { + final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); + + // Read values from world + final double typeId = environment.getBlockTypeRel(x, y, z); + final double dataValue = environment.getBlockDataRel(x, y, z); + + return queryInternal(type, data, typeId, dataValue); + } + + private Functions() { + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/NumberToken.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LexerErrorListener.java similarity index 65% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/NumberToken.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LexerErrorListener.java index 44cc70665..cb4b41ce5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/NumberToken.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LexerErrorListener.java @@ -17,28 +17,15 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.lexer.tokens; +package com.sk89q.worldedit.internal.expression; -/** - * A number. - */ -public class NumberToken extends Token { - - public final double value; - - public NumberToken(int position, double value) { - super(position); - this.value = value; - } +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; +class LexerErrorListener extends BaseErrorListener { @Override - public char id() { - return '0'; + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + throw new LexerException(charPositionInLine, msg); } - - @Override - public String toString() { - return "NumberToken(" + value + ")"; - } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/LexerException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LexerException.java similarity index 92% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/LexerException.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LexerException.java index 3e08b2732..ede88dee8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/LexerException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LexerException.java @@ -17,9 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.lexer; - -import com.sk89q.worldedit.internal.expression.ExpressionException; +package com.sk89q.worldedit.internal.expression; /** * Thrown when the lexer encounters a problem. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java new file mode 100644 index 000000000..7bfe5517c --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/LocalSlot.java @@ -0,0 +1,69 @@ +/* + * 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.internal.expression; + +/** + * Represents the metadata for a named local slot. + */ +public interface LocalSlot { + + final class Constant implements LocalSlot { + private final double value; + + public Constant(double value) { + this.value = value; + } + + @Override + public double getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + } + + final class Variable implements LocalSlot { + private double value; + + public Variable(double value) { + this.value = value; + } + + public void setValue(double value) { + this.value = value; + } + + @Override + public double getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + } + + double getValue(); + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/OperatorToken.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ParserErrorListener.java similarity index 65% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/OperatorToken.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ParserErrorListener.java index c4b70e475..937c00154 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/OperatorToken.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ParserErrorListener.java @@ -17,28 +17,15 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.lexer.tokens; +package com.sk89q.worldedit.internal.expression; -/** - * A unary or binary operator. - */ -public class OperatorToken extends Token { - - public final String operator; - - public OperatorToken(int position, String operator) { - super(position); - this.operator = operator; - } +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; +class ParserErrorListener extends BaseErrorListener { @Override - public char id() { - return 'o'; + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + throw new ParserException(charPositionInLine, msg); } - - @Override - public String toString() { - return "OperatorToken(" + operator + ")"; - } - } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ParserException.java similarity index 92% rename from worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserException.java rename to worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ParserException.java index 9a04fc914..30a3eace8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserException.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/ParserException.java @@ -17,9 +17,7 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit.internal.expression.parser; - -import com.sk89q.worldedit.internal.expression.ExpressionException; +package com.sk89q.worldedit.internal.expression; /** * Thrown when the parser encounters a problem. diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java new file mode 100644 index 000000000..e47d4200e --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/SlotTable.java @@ -0,0 +1,64 @@ +/* + * 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.internal.expression; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.Set; + +public class SlotTable { + + private final Map slots = new HashMap<>(); + + public Set keySet() { + return slots.keySet(); + } + + public void putSlot(String name, LocalSlot slot) { + slots.put(name, slot); + } + + public boolean containsSlot(String name) { + return slots.containsKey(name); + } + + public Optional initVariable(String name) { + slots.computeIfAbsent(name, n -> new LocalSlot.Variable(0)); + return getVariable(name); + } + + public Optional getSlot(String name) { + return Optional.ofNullable(slots.get(name)); + } + + public Optional getVariable(String name) { + return getSlot(name) + .filter(LocalSlot.Variable.class::isInstance) + .map(LocalSlot.Variable.class::cast); + } + + public OptionalDouble getSlotValue(String name) { + LocalSlot slot = slots.get(name); + return slot == null ? OptionalDouble.empty() : OptionalDouble.of(slot.getValue()); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/Lexer.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/Lexer.java deleted file mode 100644 index 8e5b3bbec..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/Lexer.java +++ /dev/null @@ -1,240 +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 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.internal.expression.lexer; - -import com.sk89q.worldedit.internal.expression.lexer.tokens.CharacterToken; -import com.sk89q.worldedit.internal.expression.lexer.tokens.IdentifierToken; -import com.sk89q.worldedit.internal.expression.lexer.tokens.KeywordToken; -import com.sk89q.worldedit.internal.expression.lexer.tokens.NumberToken; -import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken; -import com.sk89q.worldedit.internal.expression.lexer.tokens.Token; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Processes a string into a list of tokens. - * - *

    Tokens can be numbers, identifiers, operators and assorted other - * characters.

    - */ -public class Lexer { - - private final String expression; - private int position = 0; - - private Lexer(String expression) { - this.expression = expression; - } - - public static List tokenize(String expression) throws LexerException { - return new Lexer(expression).tokenize(); - } - - private final DecisionTree operatorTree = new DecisionTree(null, - '+', new DecisionTree("+", - '=', new DecisionTree("+="), - '+', new DecisionTree("++") - ), - '-', new DecisionTree("-", - '=', new DecisionTree("-="), - '-', new DecisionTree("--") - ), - '*', new DecisionTree("*", - '=', new DecisionTree("*="), - '*', new DecisionTree("**") - ), - '/', new DecisionTree("/", - '=', new DecisionTree("/=") - ), - '%', new DecisionTree("%", - '=', new DecisionTree("%=") - ), - '^', new DecisionTree("^", - '=', new DecisionTree("^=") - ), - '=', new DecisionTree("=", - '=', new DecisionTree("==") - ), - '!', new DecisionTree("!", - '=', new DecisionTree("!=") - ), - '<', new DecisionTree("<", - '<', new DecisionTree("<<"), - '=', new DecisionTree("<=") - ), - '>', new DecisionTree(">", - '>', new DecisionTree(">>"), - '=', new DecisionTree(">=") - ), - '&', new DecisionTree(null, // not implemented - '&', new DecisionTree("&&") - ), - '|', new DecisionTree(null, // not implemented - '|', new DecisionTree("||") - ), - '~', new DecisionTree("~", - '=', new DecisionTree("~=") - ) - ); - - private static final Set characterTokens = new HashSet<>(); - static { - characterTokens.add(','); - characterTokens.add('('); - characterTokens.add(')'); - characterTokens.add('{'); - characterTokens.add('}'); - characterTokens.add(';'); - characterTokens.add('?'); - characterTokens.add(':'); - } - - private static final Set keywords = - new HashSet<>(Arrays.asList("if", "else", "while", "do", "for", "break", "continue", "return", "switch", "case", "default")); - - private static final Pattern numberPattern = Pattern.compile("^([0-9]*(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)"); - private static final Pattern identifierPattern = Pattern.compile("^([A-Za-z][0-9A-Za-z_]*)"); - - private List tokenize() throws LexerException { - List tokens = new ArrayList<>(); - - do { - skipWhitespace(); - if (position >= expression.length()) { - break; - } - - Token token = operatorTree.evaluate(position); - if (token != null) { - tokens.add(token); - continue; - } - - final char ch = peek(); - - if (characterTokens.contains(ch)) { - tokens.add(new CharacterToken(position++, ch)); - continue; - } - - final Matcher numberMatcher = numberPattern.matcher(expression.substring(position)); - if (numberMatcher.lookingAt()) { - String numberPart = numberMatcher.group(1); - if (!numberPart.isEmpty()) { - try { - tokens.add(new NumberToken(position, Double.parseDouble(numberPart))); - } catch (NumberFormatException e) { - throw new LexerException(position, "Number parsing failed", e); - } - - position += numberPart.length(); - continue; - } - } - - final Matcher identifierMatcher = identifierPattern.matcher(expression.substring(position)); - if (identifierMatcher.lookingAt()) { - String identifierPart = identifierMatcher.group(1); - if (!identifierPart.isEmpty()) { - if (keywords.contains(identifierPart)) { - tokens.add(new KeywordToken(position, identifierPart)); - } else { - tokens.add(new IdentifierToken(position, identifierPart)); - } - - position += identifierPart.length(); - continue; - } - } - - throw new LexerException(position, "Unknown character '" + ch + "'"); - } while (position < expression.length()); - - return tokens; - } - - private char peek() { - return expression.charAt(position); - } - - private void skipWhitespace() { - while (position < expression.length() && Character.isWhitespace(peek())) { - ++position; - } - } - - public class DecisionTree { - private final String tokenName; - private final Map subTrees = new HashMap<>(); - - private DecisionTree(String tokenName, Object... args) { - this.tokenName = tokenName; - - if (args.length % 2 != 0) { - throw new UnsupportedOperationException("You need to pass an even number of arguments."); - } - - for (int i = 0; i < args.length; i += 2) { - if (!(args[i] instanceof Character)) { - throw new UnsupportedOperationException("Argument #" + i + " expected to be 'Character', not '" + args[i].getClass().getName() + "'."); - } - if (!(args[i + 1] instanceof DecisionTree)) { - throw new UnsupportedOperationException("Argument #" + (i + 1) + " expected to be 'DecisionTree', not '" + args[i + 1].getClass().getName() + "'."); - } - - Character next = (Character) args[i]; - DecisionTree subTree = (DecisionTree) args[i + 1]; - - subTrees.put(next, subTree); - } - } - - private Token evaluate(int startPosition) throws LexerException { - if (position < expression.length()) { - final char next = peek(); - - final DecisionTree subTree = subTrees.get(next); - if (subTree != null) { - ++position; - final Token subTreeResult = subTree.evaluate(startPosition); - if (subTreeResult != null) { - return subTreeResult; - } - --position; - } - } - - if (tokenName == null) { - return null; - } - - return new OperatorToken(startPosition, tokenName); - } - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/CharacterToken.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/CharacterToken.java deleted file mode 100644 index 51bf757da..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/CharacterToken.java +++ /dev/null @@ -1,44 +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 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.internal.expression.lexer.tokens; - -/** - * A single character that doesn't fit any of the other token categories. - */ -public class CharacterToken extends Token { - - public final char character; - - public CharacterToken(int position, char character) { - super(position); - this.character = character; - } - - @Override - public char id() { - return character; - } - - @Override - public String toString() { - return "CharacterToken(" + character + ")"; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/IdentifierToken.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/IdentifierToken.java deleted file mode 100644 index 4a840f754..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/IdentifierToken.java +++ /dev/null @@ -1,44 +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 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.internal.expression.lexer.tokens; - -/** - * An identifier. - */ -public class IdentifierToken extends Token { - - public final String value; - - public IdentifierToken(int position, String value) { - super(position); - this.value = value; - } - - @Override - public char id() { - return 'i'; - } - - @Override - public String toString() { - return "IdentifierToken(" + value + ")"; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/KeywordToken.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/KeywordToken.java deleted file mode 100644 index 208e7280c..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/KeywordToken.java +++ /dev/null @@ -1,44 +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 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.internal.expression.lexer.tokens; - -/** - * A keyword. - */ -public class KeywordToken extends Token { - - public final String value; - - public KeywordToken(int position, String value) { - super(position); - this.value = value; - } - - @Override - public char id() { - return 'k'; - } - - @Override - public String toString() { - return "KeywordToken(" + value + ")"; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/Token.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/Token.java deleted file mode 100644 index c6427f0c5..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/lexer/tokens/Token.java +++ /dev/null @@ -1,40 +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 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.internal.expression.lexer.tokens; - -import com.sk89q.worldedit.internal.expression.Identifiable; - -/** - * A token. The lexer generates these to make the parser's job easier. - */ -public abstract class Token implements Identifiable { - - private final int position; - - public Token(int position) { - this.position = position; - } - - @Override - public int getPosition() { - return position; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/Parser.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/Parser.java deleted file mode 100644 index 24f3dafa9..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/Parser.java +++ /dev/null @@ -1,464 +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 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.internal.expression.parser; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.Identifiable; -import com.sk89q.worldedit.internal.expression.lexer.tokens.IdentifierToken; -import com.sk89q.worldedit.internal.expression.lexer.tokens.KeywordToken; -import com.sk89q.worldedit.internal.expression.lexer.tokens.NumberToken; -import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken; -import com.sk89q.worldedit.internal.expression.lexer.tokens.Token; -import com.sk89q.worldedit.internal.expression.runtime.Break; -import com.sk89q.worldedit.internal.expression.runtime.Conditional; -import com.sk89q.worldedit.internal.expression.runtime.Constant; -import com.sk89q.worldedit.internal.expression.runtime.For; -import com.sk89q.worldedit.internal.expression.runtime.Function; -import com.sk89q.worldedit.internal.expression.runtime.Functions; -import com.sk89q.worldedit.internal.expression.runtime.LValue; -import com.sk89q.worldedit.internal.expression.runtime.RValue; -import com.sk89q.worldedit.internal.expression.runtime.Return; -import com.sk89q.worldedit.internal.expression.runtime.Sequence; -import com.sk89q.worldedit.internal.expression.runtime.SimpleFor; -import com.sk89q.worldedit.internal.expression.runtime.Switch; -import com.sk89q.worldedit.internal.expression.runtime.While; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -/** - * Processes a list of tokens into an executable tree. - * - *

    Tokens can be numbers, identifiers, operators and assorted other characters.

    - */ -public class Parser { - private final class NullToken extends Token { - private NullToken(int position) { - super(position); - } - - @Override - public char id() { - return '\0'; - } - - @Override - public String toString() { - return "NullToken"; - } - } - - private final List tokens; - private int position = 0; - private Expression expression; - - private Parser(List tokens, Expression expression) { - this.tokens = tokens; - this.expression = expression; - } - - public static RValue parse(List tokens, Expression expression) throws ParserException { - return new Parser(tokens, expression).parse(); - } - - private RValue parse() throws ParserException { - final RValue ret = parseStatements(false); - if (position < tokens.size()) { - final Token token = peek(); - throw new ParserException(token.getPosition(), "Extra token at the end of the input: " + token); - } - - ret.bindVariables(expression, false); - - return ret; - } - - private RValue parseStatements(boolean singleStatement) throws ParserException { - List statements = new ArrayList<>(); - loop: while (position < tokens.size()) { - boolean expectSemicolon = false; - - final Token current = peek(); - switch (current.id()) { - case '{': - consumeCharacter('{'); - - statements.add(parseStatements(false)); - - consumeCharacter('}'); - - break; - - case '}': - break loop; - - case 'k': - final String keyword = ((KeywordToken) current).value; - switch (keyword.charAt(0)) { - case 'i': { // if - ++position; - final RValue condition = parseBracket(); - final RValue truePart = parseStatements(true); - final RValue falsePart; - - if (hasKeyword("else")) { - ++position; - falsePart = parseStatements(true); - } else { - falsePart = null; - } - - statements.add(new Conditional(current.getPosition(), condition, truePart, falsePart)); - break; - } - - case 'w': { // while - ++position; - final RValue condition = parseBracket(); - final RValue body = parseStatements(true); - - statements.add(new While(current.getPosition(), condition, body, false)); - break; - } - - case 'd': { // do/default - if (hasKeyword("default")) { - break loop; - } - - ++position; - final RValue body = parseStatements(true); - - consumeKeyword("while"); - - final RValue condition = parseBracket(); - - statements.add(new While(current.getPosition(), condition, body, true)); - - expectSemicolon = true; - break; - } - - case 'f': { // for - ++position; - consumeCharacter('('); - int oldPosition = position; - final RValue init = parseExpression(true); - //if ((init instanceof LValue) && ) - if (peek().id() == ';') { - ++position; - final RValue condition = parseExpression(true); - consumeCharacter(';'); - final RValue increment = parseExpression(true); - consumeCharacter(')'); - final RValue body = parseStatements(true); - - statements.add(new For(current.getPosition(), init, condition, increment, body)); - } else { - position = oldPosition; - - final Token variableToken = peek(); - if (!(variableToken instanceof IdentifierToken)) { - throw new ParserException(variableToken.getPosition(), "Expected identifier"); - } - - RValue variable = expression.getVariable(((IdentifierToken) variableToken).value, true); - if (!(variable instanceof LValue)) { - throw new ParserException(variableToken.getPosition(), "Expected variable"); - } - ++position; - - final Token equalsToken = peek(); - if (!(equalsToken instanceof OperatorToken) || !((OperatorToken) equalsToken).operator.equals("=")) { - throw new ParserException(variableToken.getPosition(), "Expected '=' or a term and ';'"); - } - ++position; - - final RValue first = parseExpression(true); - consumeCharacter(','); - final RValue last = parseExpression(true); - consumeCharacter(')'); - final RValue body = parseStatements(true); - - statements.add(new SimpleFor(current.getPosition(), (LValue) variable, first, last, body)); - } // switch (keyword.charAt(0)) - break; - } - - case 'b': // break - ++position; - statements.add(new Break(current.getPosition(), false)); - break; - - case 'c': // continue/case - if (hasKeyword("case")) { - break loop; - } - - ++position; - statements.add(new Break(current.getPosition(), true)); - break; - - case 'r': // return - ++position; - statements.add(new Return(current.getPosition(), parseExpression(true))); - - expectSemicolon = true; - break; - - case 's': // switch - ++position; - final RValue parameter = parseBracket(); - final List values = new ArrayList<>(); - final List caseStatements = new ArrayList<>(); - RValue defaultCase = null; - - consumeCharacter('{'); - while (peek().id() != '}') { - if (position >= tokens.size()) { - throw new ParserException(current.getPosition(), "Expected '}' instead of EOF"); - } - if (defaultCase != null) { - throw new ParserException(current.getPosition(), "Expected '}' instead of " + peek()); - } - - if (hasKeyword("case")) { - ++position; - - final Token valueToken = peek(); - if (!(valueToken instanceof NumberToken)) { - throw new ParserException(current.getPosition(), "Expected number instead of " + peek()); - } - - ++position; - - values.add(((NumberToken) valueToken).value); - - consumeCharacter(':'); - caseStatements.add(parseStatements(false)); - } else if (hasKeyword("default")) { - ++position; - - consumeCharacter(':'); - defaultCase = parseStatements(false); - } else { - throw new ParserException(current.getPosition(), "Expected 'case' or 'default' instead of " + peek()); - } - } - consumeCharacter('}'); - - statements.add(new Switch(current.getPosition(), parameter, values, caseStatements, defaultCase)); - break; - - default: - throw new ParserException(current.getPosition(), "Unexpected keyword '" + keyword + "'"); - } - - break; - - default: - statements.add(parseExpression(true)); - - expectSemicolon = true; - } // switch (current.id()) - - if (expectSemicolon) { - if (peek().id() == ';') { - ++position; - } else { - break; - } - } - - if (singleStatement) { - break; - } - } // while (position < tokens.size()) - - switch (statements.size()) { - case 0: - if (singleStatement) { - throw new ParserException(peek().getPosition(), "Statement expected."); - } - - return new Sequence(peek().getPosition()); - - case 1: - return statements.get(0); - - default: - return new Sequence(peek().getPosition(), statements.toArray(new RValue[statements.size()])); - } - } - - private RValue parseExpression(boolean canBeEmpty) throws ParserException { - LinkedList halfProcessed = new LinkedList<>(); - - // process brackets, numbers, functions, variables and detect prefix operators - boolean expressionStart = true; - loop: while (position < tokens.size()) { - final Token current = peek(); - - switch (current.id()) { - case '0': - halfProcessed.add(new Constant(current.getPosition(), ((NumberToken) current).value)); - ++position; - expressionStart = false; - break; - - case 'i': - final IdentifierToken identifierToken = (IdentifierToken) current; - ++position; - - final Token next = peek(); - if (next.id() == '(') { - halfProcessed.add(parseFunctionCall(identifierToken)); - } else { - final RValue variable = expression.getVariable(identifierToken.value, false); - if (variable == null) { - halfProcessed.add(new UnboundVariable(identifierToken.getPosition(), identifierToken.value)); - } else { - halfProcessed.add(variable); - } - } - expressionStart = false; - break; - - case '(': - halfProcessed.add(parseBracket()); - expressionStart = false; - break; - - case ',': - case ')': - case '}': - case ';': - break loop; - - case 'o': - if (expressionStart) { - // Preprocess prefix operators into unary operators - halfProcessed.add(new UnaryOperator((OperatorToken) current)); - } else { - halfProcessed.add(current); - } - ++position; - expressionStart = true; - break; - - default: - halfProcessed.add(current); - ++position; - expressionStart = false; - break; - } - } - - if (halfProcessed.isEmpty() && canBeEmpty) { - return new Sequence(peek().getPosition()); - } - - return ParserProcessors.processExpression(halfProcessed); - } - - - private Token peek() { - if (position >= tokens.size()) { - return new NullToken(tokens.get(tokens.size() - 1).getPosition() + 1); - } - - return tokens.get(position); - } - - private Function parseFunctionCall(IdentifierToken identifierToken) throws ParserException { - consumeCharacter('('); - - try { - if (peek().id() == ')') { - ++position; - return Functions.getFunction(identifierToken.getPosition(), identifierToken.value); - } - - List args = new ArrayList<>(); - - loop: while (true) { - args.add(parseExpression(false)); - - final Token current = peek(); - ++position; - - switch (current.id()) { - case ',': - continue; - - case ')': - break loop; - - default: - throw new ParserException(current.getPosition(), "Unmatched opening bracket"); - } - } - - return Functions.getFunction(identifierToken.getPosition(), identifierToken.value, args.toArray(new RValue[args.size()])); - } catch (NoSuchMethodException e) { - throw new ParserException(identifierToken.getPosition(), "Function '" + identifierToken.value + "' not found", e); - } - } - - private RValue parseBracket() throws ParserException { - consumeCharacter('('); - - final RValue ret = parseExpression(false); - - consumeCharacter(')'); - - return ret; - } - - private boolean hasKeyword(String keyword) { - final Token next = peek(); - - return next instanceof KeywordToken && ((KeywordToken) next).value.equals(keyword); - } - - private void assertCharacter(char character) throws ParserException { - final Token next = peek(); - if (next.id() != character) { - throw new ParserException(next.getPosition(), "Expected '" + character + "'"); - } - } - - private void assertKeyword(String keyword) throws ParserException { - if (!hasKeyword(keyword)) { - throw new ParserException(peek().getPosition(), "Expected '" + keyword + "'"); - } - } - - private void consumeCharacter(char character) throws ParserException { - assertCharacter(character); - ++position; - } - - private void consumeKeyword(String keyword) throws ParserException { - assertKeyword(keyword); - ++position; - } -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserProcessors.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserProcessors.java deleted file mode 100644 index b50997cc6..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/ParserProcessors.java +++ /dev/null @@ -1,352 +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 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.internal.expression.parser; - -import com.sk89q.worldedit.internal.expression.Identifiable; -import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken; -import com.sk89q.worldedit.internal.expression.lexer.tokens.Token; -import com.sk89q.worldedit.internal.expression.runtime.Conditional; -import com.sk89q.worldedit.internal.expression.runtime.Operators; -import com.sk89q.worldedit.internal.expression.runtime.RValue; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Map; - -/** - * Helper classfor Parser. Contains processors for statements and operators. - */ -public final class ParserProcessors { - - private static final Map unaryOpMap = new HashMap<>(); - - private static final Map[] binaryOpMapsLA; - private static final Map[] binaryOpMapsRA; - - static { - unaryOpMap.put("-", "neg"); - unaryOpMap.put("!", "not"); - unaryOpMap.put("~", "inv"); - unaryOpMap.put("++", "inc"); - unaryOpMap.put("--", "dec"); - unaryOpMap.put("x++", "postinc"); - unaryOpMap.put("x--", "postdec"); - unaryOpMap.put("x!", "fac"); - - final Object[][][] binaryOpsLA = { - { - { "^", "pow" }, - { "**", "pow" }, - }, - { - { "*", "mul" }, - { "/", "div" }, - { "%", "mod" }, - }, - { - { "+", "add" }, - { "-", "sub" }, - }, - { - { "<<", "shl" }, - { ">>", "shr" }, - }, - { - { "<", "lth" }, - { ">", "gth" }, - { "<=", "leq" }, - { ">=", "geq" }, - }, - { - { "==", "equ" }, - { "!=", "neq" }, - { "~=", "near" }, - }, - { - { "&&", "and" }, - }, - { - { "||", "or" }, - }, - }; - final Object[][][] binaryOpsRA = { - { - { "=", "ass" }, - { "+=", "aadd" }, - { "-=", "asub" }, - { "*=", "amul" }, - { "/=", "adiv" }, - { "%=", "amod" }, - { "^=", "aexp" }, - }, - }; - - @SuppressWarnings("unchecked") - final Map[] lBinaryOpMapsLA = binaryOpMapsLA = new Map[binaryOpsLA.length]; - for (int i = 0; i < binaryOpsLA.length; ++i) { - final Object[][] a = binaryOpsLA[i]; - switch (a.length) { - case 0: - lBinaryOpMapsLA[i] = Collections.emptyMap(); - break; - - case 1: - final Object[] first = a[0]; - lBinaryOpMapsLA[i] = Collections.singletonMap((String) first[0], (String) first[1]); - break; - - default: - Map m = lBinaryOpMapsLA[i] = new HashMap<>(); - for (final Object[] element : a) { - m.put((String) element[0], (String) element[1]); - } - } - } - - @SuppressWarnings("unchecked") - final Map[] lBinaryOpMapsRA = binaryOpMapsRA = new Map[binaryOpsRA.length]; - for (int i = 0; i < binaryOpsRA.length; ++i) { - final Object[][] a = binaryOpsRA[i]; - switch (a.length) { - case 0: - lBinaryOpMapsRA[i] = Collections.emptyMap(); - break; - - case 1: - final Object[] first = a[0]; - lBinaryOpMapsRA[i] = Collections.singletonMap((String) first[0], (String) first[1]); - break; - - default: - Map m = lBinaryOpMapsRA[i] = new HashMap<>(); - for (final Object[] element : a) { - m.put((String) element[0], (String) element[1]); - } - } - } - } - - private ParserProcessors() { - } - - static RValue processExpression(LinkedList input) throws ParserException { - return processBinaryOpsRA(input, binaryOpMapsRA.length - 1); - } - - private static RValue processBinaryOpsLA(LinkedList input, int level) throws ParserException { - if (level < 0) { - return processUnaryOps(input); - } - - LinkedList lhs = new LinkedList<>(); - LinkedList rhs = new LinkedList<>(); - String operator = null; - - for (Iterator it = input.descendingIterator(); it.hasNext();) { - Identifiable identifiable = it.next(); - if (operator == null) { - rhs.addFirst(identifiable); - - if (!(identifiable instanceof OperatorToken)) { - continue; - } - - operator = binaryOpMapsLA[level].get(((OperatorToken) identifiable).operator); - if (operator == null) { - continue; - } - - rhs.removeFirst(); - } else { - lhs.addFirst(identifiable); - } - } - - RValue rhsInvokable = processBinaryOpsLA(rhs, level - 1); - if (operator == null) return rhsInvokable; - - RValue lhsInvokable = processBinaryOpsLA(lhs, level); - - try { - return Operators.getOperator(input.get(0).getPosition(), operator, lhsInvokable, rhsInvokable); - } catch (NoSuchMethodException e) { - final Token operatorToken = (Token) input.get(lhs.size()); - throw new ParserException(operatorToken.getPosition(), "Couldn't find operator '" + operator + "'"); - } - } - - private static RValue processBinaryOpsRA(LinkedList input, int level) throws ParserException { - if (level < 0) { - return processTernaryOps(input); - } - - LinkedList lhs = new LinkedList<>(); - LinkedList rhs = new LinkedList<>(); - String operator = null; - - for (Identifiable identifiable : input) { - if (operator == null) { - lhs.addLast(identifiable); - - if (!(identifiable instanceof OperatorToken)) { - continue; - } - - operator = binaryOpMapsRA[level].get(((OperatorToken) identifiable).operator); - if (operator == null) { - continue; - } - - lhs.removeLast(); - } else { - rhs.addLast(identifiable); - } - } - - RValue lhsInvokable = processBinaryOpsRA(lhs, level - 1); - if (operator == null) return lhsInvokable; - - RValue rhsInvokable = processBinaryOpsRA(rhs, level); - - try { - return Operators.getOperator(input.get(0).getPosition(), operator, lhsInvokable, rhsInvokable); - } catch (NoSuchMethodException e) { - final Token operatorToken = (Token) input.get(lhs.size()); - throw new ParserException(operatorToken.getPosition(), "Couldn't find operator '" + operator + "'"); - } - } - - private static RValue processTernaryOps(LinkedList input) throws ParserException { - LinkedList lhs = new LinkedList<>(); - LinkedList mhs = new LinkedList<>(); - LinkedList rhs = new LinkedList<>(); - - int partsFound = 0; - int conditionalsFound = 0; - - for (Identifiable identifiable : input) { - final char character = identifiable.id(); - switch (character) { - case '?': - ++conditionalsFound; - break; - case ':': - --conditionalsFound; - break; - } - - if (conditionalsFound < 0) { - throw new ParserException(identifiable.getPosition(), "Unexpected ':'"); - } - - switch (partsFound) { - case 0: - if (character == '?') { - partsFound = 1; - } else { - lhs.addLast(identifiable); - } - break; - - case 1: - if (conditionalsFound == 0 && character == ':') { - partsFound = 2; - } else { - mhs.addLast(identifiable); - } - break; - - case 2: - rhs.addLast(identifiable); - } - } - - if (partsFound < 2) { - return processBinaryOpsLA(input, binaryOpMapsLA.length - 1); - } - - RValue lhsInvokable = processBinaryOpsLA(lhs, binaryOpMapsLA.length - 1); - RValue mhsInvokable = processTernaryOps(mhs); - RValue rhsInvokable = processTernaryOps(rhs); - - return new Conditional(input.get(lhs.size()).getPosition(), lhsInvokable, mhsInvokable, rhsInvokable); - } - - private static RValue processUnaryOps(LinkedList input) throws ParserException { - // Preprocess postfix operators into unary operators - final Identifiable center; - LinkedList postfixes = new LinkedList<>(); - do { - if (input.isEmpty()) { - throw new ParserException(-1, "Expression missing."); - } - - final Identifiable last = input.removeLast(); - if (last instanceof OperatorToken) { - postfixes.addLast(new UnaryOperator(last.getPosition(), "x" + ((OperatorToken) last).operator)); - } else if (last instanceof UnaryOperator) { - postfixes.addLast(new UnaryOperator(last.getPosition(), "x" + ((UnaryOperator) last).operator)); - } else { - center = last; - break; - } - } while (true); - - if (!(center instanceof RValue)) { - throw new ParserException(center.getPosition(), "Expected expression, found " + center); - } - - input.addAll(postfixes); - - RValue ret = (RValue) center; - while (!input.isEmpty()) { - final Identifiable last = input.removeLast(); - final int lastPosition = last.getPosition(); - if (last instanceof UnaryOperator) { - final String operator = ((UnaryOperator) last).operator; - if (operator.equals("+")) { - continue; - } - - String opName = unaryOpMap.get(operator); - if (opName != null) { - try { - ret = Operators.getOperator(lastPosition, opName, ret); - continue; - } catch (NoSuchMethodException e) { - throw new ParserException(lastPosition, "No such prefix operator: " + operator); - } - } - } - - if (last instanceof Token) { - throw new ParserException(lastPosition, "Extra token found in expression: " + last); - } else if (last instanceof RValue) { - throw new ParserException(lastPosition, "Extra expression found: " + last); - } else { - throw new ParserException(lastPosition, "Extra element found: " + last); - } - } - return ret; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/PseudoToken.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/PseudoToken.java deleted file mode 100644 index cee19e8b3..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/PseudoToken.java +++ /dev/null @@ -1,43 +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 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.internal.expression.parser; - -import com.sk89q.worldedit.internal.expression.Identifiable; - -/** - * A pseudo-token, inserted by the parser instead of the lexer. - */ -public abstract class PseudoToken implements Identifiable { - - private final int position; - - public PseudoToken(int position) { - this.position = position; - } - - @Override - public abstract char id(); - - @Override - public int getPosition() { - return position; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnaryOperator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnaryOperator.java deleted file mode 100644 index d6a54b321..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnaryOperator.java +++ /dev/null @@ -1,50 +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 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.internal.expression.parser; - -import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken; - -/** - * The parser uses this pseudo-token to mark operators as unary operators. - */ -public class UnaryOperator extends PseudoToken { - - final String operator; - - public UnaryOperator(OperatorToken operatorToken) { - this(operatorToken.getPosition(), operatorToken.operator); - } - - public UnaryOperator(int position, String operator) { - super(position); - this.operator = operator; - } - - @Override - public char id() { - return 'p'; - } - - @Override - public String toString() { - return "UnaryOperator(" + operator + ")"; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnboundVariable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnboundVariable.java deleted file mode 100644 index a128bc866..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/parser/UnboundVariable.java +++ /dev/null @@ -1,80 +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 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.internal.expression.parser; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; -import com.sk89q.worldedit.internal.expression.runtime.LValue; -import com.sk89q.worldedit.internal.expression.runtime.RValue; - -public class UnboundVariable extends PseudoToken implements LValue { - - public final String name; - - public UnboundVariable(int position, String name) { - super(position); - this.name = name; - } - - @Override - public char id() { - return 'V'; - } - - @Override - public String toString() { - return "UnboundVariable(" + name + ")"; - } - - @Override - public double getValue() throws EvaluationException { - throw new EvaluationException(getPosition(), "Tried to evaluate unbound variable!"); - } - - @Override - public LValue optimize() throws EvaluationException { - throw new EvaluationException(getPosition(), "Tried to optimize unbound variable!"); - } - - @Override - public double assign(double value) throws EvaluationException { - throw new EvaluationException(getPosition(), "Tried to assign unbound variable!"); - } - - public RValue bind(Expression expression, boolean isLValue) throws ParserException { - final RValue variable = expression.getVariable(name, isLValue); - if (variable == null) { - throw new ParserException(getPosition(), "Variable '" + name + "' not found"); - } - - return variable; - } - - @Override - public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - final RValue variable = expression.getVariable(name, preferLValue); - if (variable == null) { - throw new ParserException(getPosition(), "Variable '" + name + "' not found"); - } - - return (LValue) variable; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Break.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Break.java deleted file mode 100644 index 00bcf9936..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Break.java +++ /dev/null @@ -1,50 +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 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.internal.expression.runtime; - -/** - * A break or continue statement. - */ -public class Break extends Node { - - boolean doContinue; - - public Break(int position, boolean doContinue) { - super(position); - - this.doContinue = doContinue; - } - - @Override - public double getValue() throws EvaluationException { - throw new BreakException(doContinue); - } - - @Override - public char id() { - return 'b'; - } - - @Override - public String toString() { - return doContinue ? "continue" : "break"; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Conditional.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Conditional.java deleted file mode 100644 index 4579004af..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Conditional.java +++ /dev/null @@ -1,93 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -/** - * An if/else statement or a ternary operator. - */ -public class Conditional extends Node { - - private RValue condition; - private RValue truePart; - private RValue falsePart; - - public Conditional(int position, RValue condition, RValue truePart, RValue falsePart) { - super(position); - - this.condition = condition; - this.truePart = truePart; - this.falsePart = falsePart; - } - - @Override - public double getValue() throws EvaluationException { - if (condition.getValue() > 0.0) { - return truePart.getValue(); - } else { - return falsePart == null ? 0.0 : falsePart.getValue(); - } - } - - @Override - public char id() { - return 'I'; - } - - @Override - public String toString() { - if (falsePart == null) { - return "if (" + condition + ") { " + truePart + " }"; - } else if (truePart instanceof Sequence || falsePart instanceof Sequence) { - return "if (" + condition + ") { " + truePart + " } else { " + falsePart + " }"; - } else { - return "(" + condition + ") ? (" + truePart + ") : (" + falsePart + ")"; - } - } - - @Override - public RValue optimize() throws EvaluationException { - final RValue newCondition = condition.optimize(); - - if (newCondition instanceof Constant) { - if (newCondition.getValue() > 0) { - return truePart.optimize(); - } else { - return falsePart == null ? new Constant(getPosition(), 0.0) : falsePart.optimize(); - } - } - - return new Conditional(getPosition(), newCondition, truePart.optimize(), falsePart == null ? null : falsePart.optimize()); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - condition = condition.bindVariables(expression, false); - truePart = truePart.bindVariables(expression, false); - if (falsePart != null) { - falsePart = falsePart.bindVariables(expression, false); - } - - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Constant.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Constant.java deleted file mode 100644 index 5bdab9e1c..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Constant.java +++ /dev/null @@ -1,49 +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 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.internal.expression.runtime; - -/** - * A constant. - */ -public final class Constant extends Node { - - private final double value; - - public Constant(int position, double value) { - super(position); - this.value = value; - } - - @Override - public double getValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - - @Override - public char id() { - return 'c'; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java deleted file mode 100644 index 6334a7350..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/For.java +++ /dev/null @@ -1,107 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -/** - * A Java/C-style for loop. - */ -public class For extends Node { - - RValue init; - RValue condition; - RValue increment; - RValue body; - - public For(int position, RValue init, RValue condition, RValue increment, RValue body) { - super(position); - - this.init = init; - this.condition = condition; - this.increment = increment; - this.body = body; - } - - @Override - public double getValue() throws EvaluationException { - int iterations = 0; - double ret = 0.0; - - for (init.getValue(); condition.getValue() > 0; increment.getValue()) { - if (iterations > 256) { - throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); - } - if (Thread.interrupted()) { - throw new EvaluationException(getPosition(), "Calculations exceeded time limit."); - } - ++iterations; - - try { - ret = body.getValue(); - } catch (BreakException e) { - if (e.doContinue) { - //noinspection UnnecessaryContinue - continue; - } else { - break; - } - } - } - - return ret; - } - - @Override - public char id() { - return 'F'; - } - - @Override - public String toString() { - return "for (" + init + "; " + condition + "; " + increment + ") { " + body + " }"; - } - - @Override - public RValue optimize() throws EvaluationException { - final RValue newCondition = condition.optimize(); - - if (newCondition instanceof Constant && newCondition.getValue() <= 0) { - // If the condition is always false, the loop can be flattened. - // So we run the init part and then return 0.0. - return new Sequence(getPosition(), init, new Constant(getPosition(), 0.0)).optimize(); - } - - //return new Sequence(getPosition(), init.optimize(), new While(getPosition(), condition, new Sequence(getPosition(), body, increment), false)).optimize(); - return new For(getPosition(), init.optimize(), newCondition, increment.optimize(), body.optimize()); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - init = init.bindVariables(expression, false); - condition = condition.bindVariables(expression, false); - increment = increment.bindVariables(expression, false); - body = body.bindVariables(expression, false); - - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Function.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Function.java deleted file mode 100644 index 1fef4a580..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Function.java +++ /dev/null @@ -1,123 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Wrapper for a Java method and its arguments (other Nodes). - */ -public class Function extends Node { - - /** - * Add this annotation on functions that don't always return the same value - * for the same inputs and on functions with side-effects. - */ - @Retention(RetentionPolicy.RUNTIME) - public @interface Dynamic { } - - final Method method; - final RValue[] args; - - Function(int position, Method method, RValue... args) { - super(position); - this.method = method; - this.args = args; - } - - @Override - public final double getValue() throws EvaluationException { - return invokeMethod(method, args); - } - - protected static double invokeMethod(Method method, Object[] args) throws EvaluationException { - try { - return (Double) method.invoke(null, args); - } catch (InvocationTargetException e) { - if (e.getTargetException() instanceof EvaluationException) { - throw (EvaluationException) e.getTargetException(); - } - throw new EvaluationException(-1, "Exception caught while evaluating expression", e.getTargetException()); - } catch (IllegalAccessException e) { - throw new EvaluationException(-1, "Internal error while evaluating expression", e); - } - } - - @Override - public String toString() { - final StringBuilder ret = new StringBuilder(method.getName()).append('('); - boolean first = true; - for (Object obj : args) { - if (!first) { - ret.append(", "); - } - first = false; - ret.append(obj); - } - return ret.append(')').toString(); - } - - @Override - public char id() { - return 'f'; - } - - @Override - public RValue optimize() throws EvaluationException { - final RValue[] optimizedArgs = new RValue[args.length]; - boolean optimizable = !method.isAnnotationPresent(Dynamic.class); - int position = getPosition(); - for (int i = 0; i < args.length; ++i) { - final RValue optimized = optimizedArgs[i] = args[i].optimize(); - - if (!(optimized instanceof Constant)) { - optimizable = false; - } - - if (optimized.getPosition() < position) { - position = optimized.getPosition(); - } - } - - if (optimizable) { - return new Constant(position, invokeMethod(method, optimizedArgs)); - } else { - return new Function(position, method, optimizedArgs); - } - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - final Class[] parameters = method.getParameterTypes(); - for (int i = 0; i < args.length; ++i) { - final boolean argumentPrefersLValue = LValue.class.isAssignableFrom(parameters[i]); - args[i] = args[i].bindVariables(expression, argumentPrefersLValue); - } - - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Functions.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Functions.java deleted file mode 100644 index d2aede416..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Functions.java +++ /dev/null @@ -1,487 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.runtime.Function.Dynamic; -import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.math.noise.PerlinNoise; -import com.sk89q.worldedit.math.noise.RidgedMultiFractalNoise; -import com.sk89q.worldedit.math.noise.VoronoiNoise; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - -/** - * Contains all functions that can be used in expressions. - */ -@SuppressWarnings("UnusedDeclaration") -public final class Functions { - - private static class Overload { - private final Method method; - private final int mask; - private final boolean isSetter; - - private Overload(Method method) throws IllegalArgumentException { - this.method = method; - - boolean isSetter = false; - int accum = 0; - Class[] parameters = method.getParameterTypes(); - for (Class parameter : parameters) { - if (isSetter) { - throw new IllegalArgumentException("Method takes arguments that can't be cast to RValue."); - } - - if (double.class.equals(parameter)) { - isSetter = true; - continue; - } - - if (!RValue.class.isAssignableFrom(parameter)) { - throw new IllegalArgumentException("Method takes arguments that can't be cast to RValue."); - } - - accum <<= 2; - - if (LValue.class.isAssignableFrom(parameter)) { - accum |= 3; - } else { - accum |= 1; - } - } - mask = accum; - this.isSetter = isSetter; - } - - public boolean matches(boolean isSetter, RValue... args) { - if (this.isSetter != isSetter) { - return false; - } - - if (this.method.getParameterTypes().length != args.length) { // TODO: optimize - return false; - } - - int accum = 0; - for (RValue argument : args) { - accum <<= 2; - - if (argument instanceof LValue) { - accum |= 3; - } else { - accum |= 1; - } - } - - return (accum & mask) == mask; - } - } - - public static Function getFunction(int position, String name, RValue... args) throws NoSuchMethodException { - final Method getter = getMethod(name, false, args); - try { - Method setter = getMethod(name, true, args); - return new LValueFunction(position, getter, setter, args); - } catch (NoSuchMethodException e) { - return new Function(position, getter, args); - } - } - - private static Method getMethod(String name, boolean isSetter, RValue... args) throws NoSuchMethodException { - final List overloads = functions.get(name); - if (overloads != null) { - for (Overload overload : overloads) { - if (overload.matches(isSetter, args)) { - return overload.method; - } - } - } - - throw new NoSuchMethodException(); // TODO: return null (check for side-effects first) - } - - private static final Map> functions = new HashMap<>(); - static { - for (Method method : Functions.class.getMethods()) { - try { - addFunction(method); - } catch (IllegalArgumentException ignored) { } - } - } - - - public static void addFunction(Method method) throws IllegalArgumentException { - final String methodName = method.getName(); - - Overload overload = new Overload(method); - - List overloads = functions.computeIfAbsent(methodName, k -> new ArrayList<>()); - - overloads.add(overload); - } - - - public static double sin(RValue x) throws EvaluationException { - return Math.sin(x.getValue()); - } - - public static double cos(RValue x) throws EvaluationException { - return Math.cos(x.getValue()); - } - - public static double tan(RValue x) throws EvaluationException { - return Math.tan(x.getValue()); - } - - - public static double asin(RValue x) throws EvaluationException { - return Math.asin(x.getValue()); - } - - public static double acos(RValue x) throws EvaluationException { - return Math.acos(x.getValue()); - } - - public static double atan(RValue x) throws EvaluationException { - return Math.atan(x.getValue()); - } - - public static double atan2(RValue y, RValue x) throws EvaluationException { - return Math.atan2(y.getValue(), x.getValue()); - } - - - public static double sinh(RValue x) throws EvaluationException { - return Math.sinh(x.getValue()); - } - - public static double cosh(RValue x) throws EvaluationException { - return Math.cosh(x.getValue()); - } - - public static double tanh(RValue x) throws EvaluationException { - return Math.tanh(x.getValue()); - } - - - public static double sqrt(RValue x) throws EvaluationException { - return Math.sqrt(x.getValue()); - } - - public static double cbrt(RValue x) throws EvaluationException { - return Math.cbrt(x.getValue()); - } - - - public static double abs(RValue x) throws EvaluationException { - return Math.abs(x.getValue()); - } - - public static double min(RValue a, RValue b) throws EvaluationException { - return Math.min(a.getValue(), b.getValue()); - } - - public static double min(RValue a, RValue b, RValue c) throws EvaluationException { - return Math.min(a.getValue(), Math.min(b.getValue(), c.getValue())); - } - - public static double max(RValue a, RValue b) throws EvaluationException { - return Math.max(a.getValue(), b.getValue()); - } - - public static double max(RValue a, RValue b, RValue c) throws EvaluationException { - return Math.max(a.getValue(), Math.max(b.getValue(), c.getValue())); - } - - - public static double ceil(RValue x) throws EvaluationException { - return Math.ceil(x.getValue()); - } - - public static double floor(RValue x) throws EvaluationException { - return Math.floor(x.getValue()); - } - - public static double rint(RValue x) throws EvaluationException { - return Math.rint(x.getValue()); - } - - public static double round(RValue x) throws EvaluationException { - return Math.round(x.getValue()); - } - - - public static double exp(RValue x) throws EvaluationException { - return Math.exp(x.getValue()); - } - - public static double ln(RValue x) throws EvaluationException { - return Math.log(x.getValue()); - } - - public static double log(RValue x) throws EvaluationException { - return Math.log(x.getValue()); - } - - public static double log10(RValue x) throws EvaluationException { - return Math.log10(x.getValue()); - } - - - public static double rotate(LValue x, LValue y, RValue angle) throws EvaluationException { - final double f = angle.getValue(); - - final double cosF = Math.cos(f); - final double sinF = Math.sin(f); - - final double xOld = x.getValue(); - final double yOld = y.getValue(); - - x.assign(xOld * cosF - yOld * sinF); - y.assign(xOld * sinF + yOld * cosF); - - return 0.0; - } - - public static double swap(LValue x, LValue y) throws EvaluationException { - final double tmp = x.getValue(); - - x.assign(y.getValue()); - y.assign(tmp); - - return 0.0; - } - - - private static final Map gmegabuf = new HashMap<>(); - private final Map megabuf = new HashMap<>(); - - public Map getMegabuf() { - return megabuf; - } - - private static double[] getSubBuffer(Map megabuf, Integer key) { - double[] ret = megabuf.get(key); - if (ret == null) { - megabuf.put(key, ret = new double[1024]); - } - return ret; - } - - private static double getBufferItem(final Map megabuf, final int index) { - return getSubBuffer(megabuf, index & ~1023)[index & 1023]; - } - - private static double setBufferItem(final Map megabuf, final int index, double value) { - return getSubBuffer(megabuf, index & ~1023)[index & 1023] = value; - } - - @Dynamic - public static double gmegabuf(RValue index) throws EvaluationException { - return getBufferItem(gmegabuf, (int) index.getValue()); - } - - @Dynamic - public static double gmegabuf(RValue index, double value) throws EvaluationException { - return setBufferItem(gmegabuf, (int) index.getValue(), value); - } - - @Dynamic - public static double megabuf(RValue index) throws EvaluationException { - return getBufferItem(Expression.getInstance().getFunctions().megabuf, (int) index.getValue()); - } - - @Dynamic - public static double megabuf(RValue index, double value) throws EvaluationException { - return setBufferItem(Expression.getInstance().getFunctions().megabuf, (int) index.getValue(), value); - } - - @Dynamic - public static double closest(RValue x, RValue y, RValue z, RValue index, RValue count, RValue stride) throws EvaluationException { - return findClosest( - Expression.getInstance().getFunctions().megabuf, - x.getValue(), - y.getValue(), - z.getValue(), - (int) index.getValue(), - (int) count.getValue(), - (int) stride.getValue() - ); - } - - @Dynamic - public static double gclosest(RValue x, RValue y, RValue z, RValue index, RValue count, RValue stride) throws EvaluationException { - return findClosest( - gmegabuf, - x.getValue(), - y.getValue(), - z.getValue(), - (int) index.getValue(), - (int) count.getValue(), - (int) stride.getValue() - ); - } - - private static double findClosest(Map megabuf, double x, double y, double z, int index, int count, int stride) { - int closestIndex = -1; - double minDistanceSquared = Double.MAX_VALUE; - - for (int i = 0; i < count; ++i) { - double currentX = getBufferItem(megabuf, index+0) - x; - double currentY = getBufferItem(megabuf, index+1) - y; - double currentZ = getBufferItem(megabuf, index+2) - z; - - double currentDistanceSquared = currentX*currentX + currentY*currentY + currentZ*currentZ; - - if (currentDistanceSquared < minDistanceSquared) { - minDistanceSquared = currentDistanceSquared; - closestIndex = index; - } - - index += stride; - } - - return closestIndex; - } - - - private static final Random random = new Random(); - - @Dynamic - public static double random() { - return random.nextDouble(); - } - - @Dynamic - public static double randint(RValue max) throws EvaluationException { - return random.nextInt((int) Math.floor(max.getValue())); - } - - private static final ThreadLocal localPerlin = ThreadLocal.withInitial(PerlinNoise::new); - - public static double perlin(RValue seed, RValue x, RValue y, RValue z, RValue frequency, RValue octaves, RValue persistence) throws EvaluationException { - PerlinNoise perlin = localPerlin.get(); - try { - perlin.setSeed((int) seed.getValue()); - perlin.setFrequency(frequency.getValue()); - perlin.setOctaveCount((int) octaves.getValue()); - perlin.setPersistence(persistence.getValue()); - } catch (IllegalArgumentException e) { - throw new EvaluationException(0, "Perlin noise error: " + e.getMessage()); - } - return perlin.noise(Vector3.at(x.getValue(), y.getValue(), z.getValue())); - } - - private static final ThreadLocal localVoronoi = ThreadLocal.withInitial(VoronoiNoise::new); - - public static double voronoi(RValue seed, RValue x, RValue y, RValue z, RValue frequency) throws EvaluationException { - VoronoiNoise voronoi = localVoronoi.get(); - try { - voronoi.setSeed((int) seed.getValue()); - voronoi.setFrequency(frequency.getValue()); - } catch (IllegalArgumentException e) { - throw new EvaluationException(0, "Voronoi error: " + e.getMessage()); - } - return voronoi.noise(Vector3.at(x.getValue(), y.getValue(), z.getValue())); - } - - private static final ThreadLocal localRidgedMulti = ThreadLocal.withInitial(RidgedMultiFractalNoise::new); - - public static double ridgedmulti(RValue seed, RValue x, RValue y, RValue z, RValue frequency, RValue octaves) throws EvaluationException { - RidgedMultiFractalNoise ridgedMulti = localRidgedMulti.get(); - try { - ridgedMulti.setSeed((int) seed.getValue()); - ridgedMulti.setFrequency(frequency.getValue()); - ridgedMulti.setOctaveCount((int) octaves.getValue()); - } catch (IllegalArgumentException e) { - throw new EvaluationException(0, "Ridged multi error: " + e.getMessage()); - } - return ridgedMulti.noise(Vector3.at(x.getValue(), y.getValue(), z.getValue())); - } - - private static double queryInternal(RValue type, RValue data, double typeId, double dataValue) throws EvaluationException { - // Compare to input values and determine return value - // -1 is a wildcard, always true - final double ret = ((type.getValue() == -1 || typeId == type.getValue()) - && (data.getValue() == -1 || dataValue == data.getValue())) ? 1.0 : 0.0; - - if (type instanceof LValue) { - ((LValue) type).assign(typeId); - } - - if (data instanceof LValue) { - ((LValue) data).assign(dataValue); - } - - return ret; - } - - @Dynamic - public static double query(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { - final double xp = x.getValue(); - final double yp = y.getValue(); - final double zp = z.getValue(); - - final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); - - // Read values from world - final double typeId = environment.getBlockType(xp, yp, zp); - final double dataValue = environment.getBlockData(xp, yp, zp); - - return queryInternal(type, data, typeId, dataValue); - } - - @Dynamic - public static double queryAbs(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { - final double xp = x.getValue(); - final double yp = y.getValue(); - final double zp = z.getValue(); - - final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); - - // Read values from world - final double typeId = environment.getBlockTypeAbs(xp, yp, zp); - final double dataValue = environment.getBlockDataAbs(xp, yp, zp); - - return queryInternal(type, data, typeId, dataValue); - } - - @Dynamic - public static double queryRel(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException { - final double xp = x.getValue(); - final double yp = y.getValue(); - final double zp = z.getValue(); - - final ExpressionEnvironment environment = Expression.getInstance().getEnvironment(); - - // Read values from world - final double typeId = environment.getBlockTypeRel(xp, yp, zp); - final double dataValue = environment.getBlockDataRel(xp, yp, zp); - - return queryInternal(type, data, typeId, dataValue); - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValue.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValue.java deleted file mode 100644 index 338cc74b2..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValue.java +++ /dev/null @@ -1,38 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -/** - * A value that can be used on the left side of an assignment. - */ -public interface LValue extends RValue { - - double assign(double value) throws EvaluationException; - - @Override - LValue optimize() throws EvaluationException; - - @Override - LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException; - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValueFunction.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValueFunction.java deleted file mode 100644 index de145514a..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/LValueFunction.java +++ /dev/null @@ -1,77 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -import java.lang.reflect.Method; - -/** - * Wrapper for a pair of Java methods and their arguments (other Nodes), - * forming an LValue. - */ -public class LValueFunction extends Function implements LValue { - - private final Object[] setterArgs; - private final Method setter; - - LValueFunction(int position, Method getter, Method setter, RValue... args) { - super(position, getter, args); - assert (getter.isAnnotationPresent(Dynamic.class)); - - setterArgs = new Object[args.length + 1]; - System.arraycopy(args, 0, setterArgs, 0, args.length); - this.setter = setter; - } - - @Override - public char id() { - return 'l'; - } - - @Override - public double assign(double value) throws EvaluationException { - setterArgs[setterArgs.length - 1] = value; - return invokeMethod(setter, setterArgs); - } - - @Override - public LValue optimize() throws EvaluationException { - final RValue optimized = super.optimize(); - if (optimized == this) { - return this; - } - - if (optimized instanceof Function) { - return new LValueFunction(optimized.getPosition(), method, setter, ((Function) optimized).args); - } - - return (LValue) optimized; - } - - @Override - public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - super.bindVariables(expression, preferLValue); - - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Node.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Node.java deleted file mode 100644 index 1c1836c4d..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Node.java +++ /dev/null @@ -1,54 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -/** - * A node in the execution tree of an expression. - */ -public abstract class Node implements RValue { - - private final int position; - - public Node(int position) { - this.position = position; - } - - @Override - public abstract String toString(); - - @Override - public RValue optimize() throws EvaluationException { - return this; - } - - @Override - public final int getPosition() { - return position; - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Operators.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Operators.java deleted file mode 100644 index cb4f9d78b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Operators.java +++ /dev/null @@ -1,228 +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 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.internal.expression.runtime; - -/** - * Contains all unary and binary operators. - */ -@SuppressWarnings("UnusedDeclaration") -public final class Operators { - - private Operators() { - } - - public static Function getOperator(int position, String name, RValue lhs, RValue rhs) throws NoSuchMethodException { - if (lhs instanceof LValue) { - try { - return new Function(position, Operators.class.getMethod(name, LValue.class, RValue.class), lhs, rhs); - } catch (NoSuchMethodException ignored) { } - } - return new Function(position, Operators.class.getMethod(name, RValue.class, RValue.class), lhs, rhs); - } - - public static Function getOperator(int position, String name, RValue argument) throws NoSuchMethodException { - if (argument instanceof LValue) { - try { - return new Function(position, Operators.class.getMethod(name, LValue.class), argument); - } catch (NoSuchMethodException ignored) { } - } - return new Function(position, Operators.class.getMethod(name, RValue.class), argument); - } - - - public static double add(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() + rhs.getValue(); - } - - public static double sub(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() - rhs.getValue(); - } - - public static double mul(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() * rhs.getValue(); - } - - public static double div(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() / rhs.getValue(); - } - - public static double mod(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() % rhs.getValue(); - } - - public static double pow(RValue lhs, RValue rhs) throws EvaluationException { - return Math.pow(lhs.getValue(), rhs.getValue()); - } - - - public static double neg(RValue x) throws EvaluationException { - return -x.getValue(); - } - - public static double not(RValue x) throws EvaluationException { - return x.getValue() > 0.0 ? 0.0 : 1.0; - } - - public static double inv(RValue x) throws EvaluationException { - return ~(long) x.getValue(); - } - - - public static double lth(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() < rhs.getValue() ? 1.0 : 0.0; - } - - public static double gth(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() > rhs.getValue() ? 1.0 : 0.0; - } - - public static double leq(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() <= rhs.getValue() ? 1.0 : 0.0; - } - - public static double geq(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() >= rhs.getValue() ? 1.0 : 0.0; - } - - - public static double equ(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() == rhs.getValue() ? 1.0 : 0.0; - } - - public static double neq(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() != rhs.getValue() ? 1.0 : 0.0; - } - - public static double near(RValue lhs, RValue rhs) throws EvaluationException { - return almostEqual2sComplement(lhs.getValue(), rhs.getValue(), 450359963L) ? 1.0 : 0.0; - //return Math.abs(lhs.invoke() - rhs.invoke()) < 1e-7 ? 1.0 : 0.0; - } - - - public static double or(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() > 0.0 || rhs.getValue() > 0.0 ? 1.0 : 0.0; - } - - public static double and(RValue lhs, RValue rhs) throws EvaluationException { - return lhs.getValue() > 0.0 && rhs.getValue() > 0.0 ? 1.0 : 0.0; - } - - - public static double shl(RValue lhs, RValue rhs) throws EvaluationException { - return (long) lhs.getValue() << (long) rhs.getValue(); - } - - public static double shr(RValue lhs, RValue rhs) throws EvaluationException { - return (long) lhs.getValue() >> (long) rhs.getValue(); - } - - - public static double ass(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(rhs.getValue()); - } - - public static double aadd(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(lhs.getValue() + rhs.getValue()); - } - - public static double asub(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(lhs.getValue() - rhs.getValue()); - } - - public static double amul(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(lhs.getValue() * rhs.getValue()); - } - - public static double adiv(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(lhs.getValue() / rhs.getValue()); - } - - public static double amod(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(lhs.getValue() % rhs.getValue()); - } - - public static double aexp(LValue lhs, RValue rhs) throws EvaluationException { - return lhs.assign(Math.pow(lhs.getValue(), rhs.getValue())); - } - - - public static double inc(LValue x) throws EvaluationException { - return x.assign(x.getValue() + 1); - } - - public static double dec(LValue x) throws EvaluationException { - return x.assign(x.getValue() - 1); - } - - public static double postinc(LValue x) throws EvaluationException { - final double oldValue = x.getValue(); - x.assign(oldValue + 1); - return oldValue; - } - - public static double postdec(LValue x) throws EvaluationException { - final double oldValue = x.getValue(); - x.assign(oldValue - 1); - return oldValue; - } - - - private static final double[] factorials = new double[171]; - static { - double accum = 1; - factorials[0] = 1; - for (int i = 1; i < factorials.length; ++i) { - factorials[i] = accum *= i; - } - } - - public static double fac(RValue x) throws EvaluationException { - final int n = (int) x.getValue(); - - if (n < 0) { - return 0; - } - - if (n >= factorials.length) { - return Double.POSITIVE_INFINITY; - } - - return factorials[n]; - } - - // Usable AlmostEqual function, based on http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm - private static boolean almostEqual2sComplement(double a, double b, long maxUlps) { - // Make sure maxUlps is non-negative and small enough that the - // default NAN won't compare as equal to anything. - //assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); // this is for floats, not doubles - - long aLong = Double.doubleToRawLongBits(a); - // Make aLong lexicographically ordered as a twos-complement long - if (aLong < 0) aLong = 0x8000000000000000L - aLong; - - long bLong = Double.doubleToRawLongBits(b); - // Make bLong lexicographically ordered as a twos-complement long - if (bLong < 0) bLong = 0x8000000000000000L - bLong; - - final long longDiff = Math.abs(aLong - bLong); - return longDiff <= maxUlps; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/RValue.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/RValue.java deleted file mode 100644 index 45a654bcd..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/RValue.java +++ /dev/null @@ -1,37 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.Identifiable; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -/** - * A value that can be used on the right side of an assignment. - */ -public interface RValue extends Identifiable { - - double getValue() throws EvaluationException; - - RValue optimize() throws EvaluationException; - - RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException; - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Return.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Return.java deleted file mode 100644 index 455a09a3b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Return.java +++ /dev/null @@ -1,60 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -/** - * A return statement. - */ -public class Return extends Node { - - RValue value; - - public Return(int position, RValue value) { - super(position); - - this.value = value; - } - - @Override - public double getValue() throws EvaluationException { - throw new ReturnException(value.getValue()); - } - - @Override - public char id() { - return 'r'; - } - - @Override - public String toString() { - return "return " + value; - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - value = value.bindVariables(expression, false); - - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ReturnException.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ReturnException.java deleted file mode 100644 index 84b60021b..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/ReturnException.java +++ /dev/null @@ -1,41 +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 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.internal.expression.runtime; - -/** - * Thrown when a return statement is encountered. - * {@link com.sk89q.worldedit.internal.expression.Expression#evaluate} - * catches this exception and returns the enclosed value. - */ -public class ReturnException extends EvaluationException { - - final double value; - - public ReturnException(double value) { - super(-1); - - this.value = value; - } - - public double getValue() { - return value; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Sequence.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Sequence.java deleted file mode 100644 index f6458acce..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Sequence.java +++ /dev/null @@ -1,109 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * A sequence of operations, usually separated by semicolons in the - * input stream. - */ -public class Sequence extends Node { - - final RValue[] sequence; - - public Sequence(int position, RValue... sequence) { - super(position); - - this.sequence = sequence; - } - - @Override - public char id() { - return 's'; - } - - @Override - public double getValue() throws EvaluationException { - double ret = 0; - for (RValue invokable : sequence) { - ret = invokable.getValue(); - } - return ret; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("seq("); - boolean first = true; - for (RValue invokable : sequence) { - if (!first) { - sb.append(", "); - } - sb.append(invokable); - first = false; - } - - return sb.append(')').toString(); - } - - @Override - public RValue optimize() throws EvaluationException { - final List newSequence = new ArrayList<>(); - - RValue droppedLast = null; - for (RValue invokable : sequence) { - droppedLast = null; - invokable = invokable.optimize(); - if (invokable instanceof Sequence) { - Collections.addAll(newSequence, ((Sequence) invokable).sequence); - } else if (invokable instanceof Constant) { - droppedLast = invokable; - } else { - newSequence.add(invokable); - } - } - - if (droppedLast != null) { - newSequence.add(droppedLast); - } - - if (newSequence.size() == 1) { - return newSequence.get(0); - } - - return new Sequence(getPosition(), newSequence.toArray(new RValue[newSequence.size()])); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - for (int i = 0; i < sequence.length; ++i) { - sequence[i] = sequence[i].bindVariables(expression, false); - } - - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/SimpleFor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/SimpleFor.java deleted file mode 100644 index 1576c3484..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/SimpleFor.java +++ /dev/null @@ -1,104 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -/** - * A simple-style for loop. - */ -public class SimpleFor extends Node { - - LValue counter; - RValue first; - RValue last; - RValue body; - - public SimpleFor(int position, LValue counter, RValue first, RValue last, RValue body) { - super(position); - - this.counter = counter; - this.first = first; - this.last = last; - this.body = body; - } - - @Override - public double getValue() throws EvaluationException { - int iterations = 0; - double ret = 0.0; - - double firstValue = first.getValue(); - double lastValue = last.getValue(); - - for (double i = firstValue; i <= lastValue; ++i) { - if (iterations > 256) { - throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); - } - if (Thread.interrupted()) { - throw new EvaluationException(getPosition(), "Calculations exceeded time limit."); - } - ++iterations; - - try { - counter.assign(i); - ret = body.getValue(); - } catch (BreakException e) { - if (e.doContinue) { - //noinspection UnnecessaryContinue - continue; - } else { - break; - } - } - } - - return ret; - } - - @Override - public char id() { - return 'S'; - } - - @Override - public String toString() { - return "for (" + counter + " = " + first + ", " + last + ") { " + body + " }"; - } - - @Override - public RValue optimize() throws EvaluationException { - // TODO: unroll small loops into Sequences - - return new SimpleFor(getPosition(), counter.optimize(), first.optimize(), last.optimize(), body.optimize()); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - counter = counter.bindVariables(expression, true); - first = first.bindVariables(expression, false); - last = last.bindVariables(expression, false); - body = body.bindVariables(expression, false); - - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Switch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Switch.java deleted file mode 100644 index 9f2f35764..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Switch.java +++ /dev/null @@ -1,206 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * A switch/case construct. - */ -public class Switch extends Node implements RValue { - - private RValue parameter; - private final Map valueMap; - private final RValue[] caseStatements; - private RValue defaultCase; - - public Switch(int position, RValue parameter, List values, List caseStatements, RValue defaultCase) { - this(position, parameter, invertList(values), caseStatements, defaultCase); - - } - - private static Map invertList(List values) { - Map valueMap = new HashMap<>(); - for (int i = 0; i < values.size(); ++i) { - valueMap.put(values.get(i), i); - } - return valueMap; - } - - private Switch(int position, RValue parameter, Map valueMap, List caseStatements, RValue defaultCase) { - super(position); - - this.parameter = parameter; - this.valueMap = valueMap; - this.caseStatements = caseStatements.toArray(new RValue[caseStatements.size()]); - this.defaultCase = defaultCase; - } - - @Override - public char id() { - return 'W'; - } - - @Override - public double getValue() throws EvaluationException { - final double parameter = this.parameter.getValue(); - - try { - double ret = 0.0; - - final Integer index = valueMap.get(parameter); - if (index != null) { - for (int i = index; i < caseStatements.length; ++i) { - ret = caseStatements[i].getValue(); - } - } - - return defaultCase == null ? ret : defaultCase.getValue(); - } catch (BreakException e) { - if (e.doContinue) throw e; - - return 0.0; - } - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - - sb.append("switch ("); - sb.append(parameter); - sb.append(") { "); - - for (int i = 0; i < caseStatements.length; ++i) { - RValue caseStatement = caseStatements[i]; - sb.append("case "); - for (Entry entry : valueMap.entrySet()) { - if (entry.getValue() == i) { - sb.append(entry.getKey()); - break; - } - } - sb.append(": "); - sb.append(caseStatement); - sb.append(' '); - } - - if (defaultCase != null) { - sb.append("default: "); - sb.append(defaultCase); - sb.append(' '); - } - - sb.append("}"); - - return sb.toString(); - } - - @Override - public RValue optimize() throws EvaluationException { - final RValue optimizedParameter = parameter.optimize(); - final List newSequence = new ArrayList<>(); - - if (optimizedParameter instanceof Constant) { - final double parameter = optimizedParameter.getValue(); - - final Integer index = valueMap.get(parameter); - if (index == null) { - return defaultCase == null ? new Constant(getPosition(), 0.0) : defaultCase.optimize(); - } - - boolean breakDetected = false; - for (int i = index; i < caseStatements.length && !breakDetected; ++i) { - final RValue invokable = caseStatements[i].optimize(); - - if (invokable instanceof Sequence) { - for (RValue subInvokable : ((Sequence) invokable).sequence) { - if (subInvokable instanceof Break) { - breakDetected = true; - break; - } - - newSequence.add(subInvokable); - } - } else { - newSequence.add(invokable); - } - } - - if (defaultCase != null && !breakDetected) { - final RValue invokable = defaultCase.optimize(); - - if (invokable instanceof Sequence) { - Collections.addAll(newSequence, ((Sequence) invokable).sequence); - } else { - newSequence.add(invokable); - } - } - - return new Switch(getPosition(), optimizedParameter, Collections.singletonMap(parameter, 0), newSequence, null); - } - - final Map newValueMap = new HashMap<>(); - - Map backMap = new HashMap<>(); - for (Entry entry : valueMap.entrySet()) { - backMap.put(entry.getValue(), entry.getKey()); - } - - for (int i = 0; i < caseStatements.length; ++i) { - final RValue invokable = caseStatements[i].optimize(); - - final Double caseValue = backMap.get(i); - if (caseValue != null) { - newValueMap.put(caseValue, newSequence.size()); - } - - if (invokable instanceof Sequence) { - Collections.addAll(newSequence, ((Sequence) invokable).sequence); - } else { - newSequence.add(invokable); - } - } - - return new Switch(getPosition(), optimizedParameter, newValueMap, newSequence, defaultCase.optimize()); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - parameter = parameter.bindVariables(expression, false); - - for (int i = 0; i < caseStatements.length; ++i) { - caseStatements[i] = caseStatements[i].bindVariables(expression, false); - } - - defaultCase = defaultCase.bindVariables(expression, false); - - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Variable.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Variable.java deleted file mode 100644 index 01fe6764f..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/Variable.java +++ /dev/null @@ -1,67 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -/** - * A variable. - */ -public final class Variable extends Node implements LValue { - - public double value; - - public Variable(double value) { - super(-1); - this.value = value; - } - - @Override - public double getValue() { - return value; - } - - @Override - public String toString() { - return "var"; - } - - @Override - public char id() { - return 'v'; - } - - @Override - public double assign(double value) { - return this.value = value; - } - - @Override - public LValue optimize() throws EvaluationException { - return this; - } - - @Override - public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/While.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/While.java deleted file mode 100644 index 5da3dae01..000000000 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/runtime/While.java +++ /dev/null @@ -1,133 +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 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.internal.expression.runtime; - -import com.sk89q.worldedit.internal.expression.Expression; -import com.sk89q.worldedit.internal.expression.parser.ParserException; - -/** - * A while loop. - */ -public class While extends Node { - - RValue condition; - RValue body; - boolean footChecked; - - public While(int position, RValue condition, RValue body, boolean footChecked) { - super(position); - - this.condition = condition; - this.body = body; - this.footChecked = footChecked; - } - - @Override - public double getValue() throws EvaluationException { - int iterations = 0; - double ret = 0.0; - - if (footChecked) { - do { - if (iterations > 256) { - throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); - } - if (Thread.interrupted()) { - throw new EvaluationException(getPosition(), "Calculations exceeded time limit."); - } - ++iterations; - - try { - ret = body.getValue(); - } catch (BreakException e) { - if (e.doContinue) { - continue; - } else { - break; - } - } - } while (condition.getValue() > 0.0); - } else { - while (condition.getValue() > 0.0) { - if (iterations > 256) { - throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations."); - } - if (Thread.interrupted()) { - throw new EvaluationException(getPosition(), "Calculations exceeded time limit."); - } - ++iterations; - - try { - ret = body.getValue(); - } catch (BreakException e) { - if (e.doContinue) { - //noinspection UnnecessaryContinue - continue; - } else { - break; - } - } - } - } - - return ret; - } - - @Override - public char id() { - return 'w'; - } - - @Override - public String toString() { - if (footChecked) { - return "do { " + body + " } while (" + condition + ")"; - } else { - return "while (" + condition + ") { " + body + " }"; - } - } - - @Override - public RValue optimize() throws EvaluationException { - final RValue newCondition = condition.optimize(); - - if (newCondition instanceof Constant && newCondition.getValue() <= 0) { - // If the condition is always false, the loop can be flattened. - if (footChecked) { - // Foot-checked loops run at least once. - return body.optimize(); - } else { - // Loops that never run always return 0.0. - return new Constant(getPosition(), 0.0); - } - } - - return new While(getPosition(), newCondition, body.optimize(), footChecked); - } - - @Override - public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException { - condition = condition.bindVariables(expression, false); - body = body.bindVariables(expression, false); - - return this; - } - -} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java index 2304e4876..d4719fc52 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/shape/WorldEditExpressionEnvironment.java @@ -20,7 +20,7 @@ package com.sk89q.worldedit.regions.shape; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; +import com.sk89q.worldedit.internal.expression.ExpressionEnvironment; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java index de9cce3cc..c33112f05 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java @@ -22,20 +22,17 @@ package com.sk89q.worldedit.internal.expression; import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.extension.platform.Platform; -import com.sk89q.worldedit.internal.expression.lexer.LexerException; -import com.sk89q.worldedit.internal.expression.parser.ParserException; -import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; -import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment; -import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.time.Duration; + import static java.lang.Math.atan2; import static java.lang.Math.sin; -import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -79,71 +76,71 @@ public class ExpressionTest { @Test public void testErrors() { - assertAll( - // test lexer errors - () -> { - LexerException e = assertThrows(LexerException.class, - () -> compile("#")); - assertEquals(0, e.getPosition(), "Error position"); - }, - // test parser errors - () -> { - ParserException e = assertThrows(ParserException.class, - () -> compile("x")); - assertEquals(0, e.getPosition(), "Error position"); - }, - () -> { - ParserException e = assertThrows(ParserException.class, - () -> compile("x()")); - assertEquals(0, e.getPosition(), "Error position"); - }, - () -> assertThrows(ParserException.class, - () -> compile("(")), - () -> assertThrows(ParserException.class, - () -> compile("x(")), - // test overloader errors - () -> { - ParserException e = assertThrows(ParserException.class, - () -> compile("atan2(1)")); - assertEquals(0, e.getPosition(), "Error position"); - }, - () -> { - ParserException e = assertThrows(ParserException.class, - () -> compile("atan2(1, 2, 3)")); - assertEquals(0, e.getPosition(), "Error position"); - }, - () -> { - ParserException e = assertThrows(ParserException.class, - () -> compile("rotate(1, 2, 3)")); - assertEquals(0, e.getPosition(), "Error position"); - } - ); + // test lexer errors + { + ExpressionException e = assertThrows(ExpressionException.class, + () -> compile("#")); + assertEquals(0, e.getPosition(), "Error position"); + } + // test parser errors + { + ExpressionException e = assertThrows(ExpressionException.class, + () -> compile("x")); + assertEquals(0, e.getPosition(), "Error position"); + } + { + ExpressionException e = assertThrows(ExpressionException.class, + () -> compile("x()")); + assertEquals(0, e.getPosition(), "Error position"); + } + assertThrows(ExpressionException.class, + () -> compile("(")); + assertThrows(ExpressionException.class, + () -> compile("x(")); + // test overloader errors + { + ExpressionException e = assertThrows(ExpressionException.class, + () -> compile("atan2(1)")); + assertEquals(0, e.getPosition(), "Error position"); + } + { + ExpressionException e = assertThrows(ExpressionException.class, + () -> compile("atan2(1, 2, 3)")); + assertEquals(0, e.getPosition(), "Error position"); + } + { + ExpressionException e = assertThrows(ExpressionException.class, + () -> compile("rotate(1, 2, 3)")); + e.printStackTrace(); + assertEquals(7, e.getPosition(), "Error position"); + } + } @Test public void testAssign() throws ExpressionException { Expression foo = compile("{a=x} b=y; c=z", "x", "y", "z", "a", "b", "c"); foo.evaluate(2D, 3D, 5D); - assertEquals(2, foo.getVariable("a", false).getValue(), 0); - assertEquals(3, foo.getVariable("b", false).getValue(), 0); - assertEquals(5, foo.getVariable("c", false).getValue(), 0); + assertEquals(2, foo.getSlots().getSlotValue("a").orElse(-1), 0); + assertEquals(3, foo.getSlots().getSlotValue("b").orElse(-1), 0); + assertEquals(5, foo.getSlots().getSlotValue("c").orElse(-1), 0); } @Test public void testIf() throws ExpressionException { - assertEquals(40, simpleEval("if (1) x=4; else y=5; x*10+y;"), 0); - assertEquals(5, simpleEval("if (0) x=4; else y=5; x*10+y;"), 0); + assertEquals(40, simpleEval("y=0; if (1) x=4; else y=5; x*10+y;"), 0); + assertEquals(5, simpleEval("x=0; if (0) x=4; else y=5; x*10+y;"), 0); // test 'dangling else' final Expression expression1 = compile("if (1) if (0) x=4; else y=5;", "x", "y"); expression1.evaluate(1D, 2D); - assertEquals(1, expression1.getVariable("x", false).getValue(), 0); - assertEquals(5, expression1.getVariable("y", false).getValue(), 0); + assertEquals(1, expression1.getSlots().getSlotValue("x").orElse(-1), 0); + assertEquals(5, expression1.getSlots().getSlotValue("y").orElse(-1), 0); // test if the if construct is correctly recognized as a statement final Expression expression2 = compile("if (0) if (1) x=5; y=4;", "x", "y"); expression2.evaluate(1D, 2D); - assertEquals(4, expression2.getVariable("y", false).getValue(), 0); + assertEquals(4, expression2.getSlots().getSlotValue("y").orElse(-1), 0); } @Test @@ -182,9 +179,11 @@ public class ExpressionTest { @Test public void testTimeout() { - ExpressionTimeoutException e = assertThrows(ExpressionTimeoutException.class, - () -> simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"), - "Loop was not stopped."); + ExpressionTimeoutException e = assertTimeoutPreemptively(Duration.ofSeconds(10), () -> + assertThrows(ExpressionTimeoutException.class, + () -> simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"), + "Loop was not stopped.") + ); assertTrue(e.getMessage().contains("Calculations exceeded time limit")); } @@ -226,7 +225,7 @@ public class ExpressionTest { return expression.evaluate(); } - private Expression compile(String expressionString, String... variableNames) throws ExpressionException, EvaluationException { + private Expression compile(String expressionString, String... variableNames) throws ExpressionException { final Expression expression = Expression.compile(expressionString, variableNames); expression.optimize(); return expression; From a273e55e7ab57acd7e759bd12a0682e465b9a137 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Fri, 18 Oct 2019 22:39:52 -0700 Subject: [PATCH 353/366] Fix gradle build --- config/checkstyle/import-control.xml | 4 ++++ worldedit-core/build.gradle.kts | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml index 07b74fba9..67f78b649 100644 --- a/config/checkstyle/import-control.xml +++ b/config/checkstyle/import-control.xml @@ -42,6 +42,10 @@ + + + + diff --git a/worldedit-core/build.gradle.kts b/worldedit-core/build.gradle.kts index 19dcecc05..188dc7430 100644 --- a/worldedit-core/build.gradle.kts +++ b/worldedit-core/build.gradle.kts @@ -1,3 +1,4 @@ +import net.minecrell.gradle.licenser.LicenseExtension import org.gradle.plugins.ide.idea.model.IdeaModel plugins { @@ -52,6 +53,15 @@ tasks.named("generateGrammarSource").configure { ) } +configure { + exclude { + it.file.startsWith(project.buildDir) + } +} +tasks.withType().configureEach { + exclude("com/sk89q/worldedit/antlr/**/*.java") +} + // Give intellij info about where ANTLR code comes from plugins.withId("idea") { configure { From 91a78f725a14e14fcad55046af39c879a692357e Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 19 Oct 2019 00:48:49 -0700 Subject: [PATCH 354/366] Some shading fixes --- buildSrc/src/main/kotlin/PlatformConfig.kt | 1 + worldedit-bukkit/build.gradle.kts | 2 ++ worldedit-fabric/build.gradle.kts | 2 ++ worldedit-forge/build.gradle.kts | 2 ++ 4 files changed, 7 insertions(+) diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index beb159945..68dd492df 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -110,6 +110,7 @@ fun Project.applyShadowConfiguration() { exclude("GradleStart**") exclude(".cache") exclude("LICENSE*") + exclude("META-INF/maven/**") minimize() } } diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index cb859fb6a..1f9d54c7c 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -54,9 +54,11 @@ tasks.named("shadowJar") { dependencies { relocate("org.slf4j", "com.sk89q.worldedit.slf4j") relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge") + relocate("org.antlr.v4", "com.sk89q.worldedit.antlr4") include(dependency(":worldedit-core")) 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.5")) } diff --git a/worldedit-fabric/build.gradle.kts b/worldedit-fabric/build.gradle.kts index 84d19a01e..fa38ce619 100644 --- a/worldedit-fabric/build.gradle.kts +++ b/worldedit-fabric/build.gradle.kts @@ -73,9 +73,11 @@ tasks.named("shadowJar") { dependencies { relocate("org.slf4j", "com.sk89q.worldedit.slf4j") relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge") + relocate("org.antlr.v4", "com.sk89q.worldedit.antlr4") include(dependency("org.slf4j:slf4j-api")) include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + include(dependency("org.antlr:antlr4-runtime")) } } diff --git a/worldedit-forge/build.gradle.kts b/worldedit-forge/build.gradle.kts index b339aa62b..9d0ea3e3f 100644 --- a/worldedit-forge/build.gradle.kts +++ b/worldedit-forge/build.gradle.kts @@ -87,9 +87,11 @@ tasks.named("shadowJar") { dependencies { relocate("org.slf4j", "com.sk89q.worldedit.slf4j") relocate("org.apache.logging.slf4j", "com.sk89q.worldedit.log4jbridge") + relocate("org.antlr.v4", "com.sk89q.worldedit.antlr4") include(dependency("org.slf4j:slf4j-api")) include(dependency("org.apache.logging.log4j:log4j-slf4j-impl")) + include(dependency("org.antlr:antlr4-runtime")) include(dependency("de.schlichtherle:truezip")) include(dependency("org.mozilla:rhino")) } From b0528f157aaddc71474b9c23e006e6eba760df58 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 26 Oct 2019 16:18:59 -0700 Subject: [PATCH 355/366] Improve timeout tracking for expressions --- .../com/sk89q/worldedit/internal/expression/Expression.java | 4 ++++ worldedit-core/src/test/resources/junit-platform.properties | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java index 9bca48e12..147378934 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java @@ -37,6 +37,7 @@ import java.lang.invoke.MethodHandle; import java.util.List; import java.util.Objects; import java.util.Stack; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -141,6 +142,7 @@ public class Expression { } private double evaluateRootTimed(int timeout) throws EvaluationException { + CountDownLatch startLatch = new CountDownLatch(1); Request request = Request.request(); Future result = evalThread.submit(() -> { Request local = Request.request(); @@ -148,12 +150,14 @@ public class Expression { local.setWorld(request.getWorld()); local.setEditSession(request.getEditSession()); try { + startLatch.countDown(); return Expression.this.evaluateRoot(); } finally { Request.reset(); } }); try { + startLatch.await(); return result.get(timeout, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/worldedit-core/src/test/resources/junit-platform.properties b/worldedit-core/src/test/resources/junit-platform.properties index ee7c4fad3..31bfedd9e 100644 --- a/worldedit-core/src/test/resources/junit-platform.properties +++ b/worldedit-core/src/test/resources/junit-platform.properties @@ -2,4 +2,4 @@ junit.jupiter.execution.parallel.enabled=true junit.jupiter.execution.parallel.mode.default=concurrent junit.jupiter.execution.parallel.mode.classes.default=same_thread junit.jupiter.execution.parallel.config.strategy=dynamic -junit.jupiter.execution.parallel.config.dynamic.factor=4 +junit.jupiter.execution.parallel.config.dynamic.factor=1 From fa42e4028189c8a4fb1ac80d9db30368de4c700b Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 26 Oct 2019 16:44:23 -0700 Subject: [PATCH 356/366] Limit expression thread count to processor count. --- .../worldedit/internal/expression/Expression.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java index 147378934..90e437136 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/expression/Expression.java @@ -74,11 +74,12 @@ import java.util.concurrent.TimeoutException; public class Expression { private static final ThreadLocal> instance = new ThreadLocal<>(); - private static final ExecutorService evalThread = Executors.newCachedThreadPool( - new ThreadFactoryBuilder() - .setDaemon(true) - .setNameFormat("worldedit-expression-eval-%d") - .build()); + private static final ExecutorService evalThread = Executors.newFixedThreadPool( + Runtime.getRuntime().availableProcessors(), + new ThreadFactoryBuilder() + .setDaemon(true) + .setNameFormat("worldedit-expression-eval-%d") + .build()); private final SlotTable slots = new SlotTable(); private final List providedSlots; From ae71c2a51b10b9dcc72e92055a0c228101be0f15 Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sat, 26 Oct 2019 16:51:13 -0700 Subject: [PATCH 357/366] Clean up formatting on ANTLR grammar --- .../com/sk89q/worldedit/antlr/Expression.g4 | 118 +++++++++--------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 index c98965af6..107aa5176 100644 --- a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 +++ b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 @@ -130,13 +130,13 @@ emptyStatement: SEMI_COLON ; expression : assignmentExpression ; assignmentExpression - : conditionalExpression - | assignment - ; + : conditionalExpression + | assignment + ; assignment - : target=ID assignmentOperator source=expression - ; + : target=ID assignmentOperator source=expression + ; assignmentOperator : ASSIGN @@ -149,80 +149,80 @@ assignmentOperator ; conditionalExpression - : conditionalOrExpression # CEFallthrough - | condition=conditionalOrExpression QUESTION_MARK - trueBranch=expression COLON falseBranch=conditionalExpression # TernaryExpr - ; + : conditionalOrExpression # CEFallthrough + | condition=conditionalOrExpression QUESTION_MARK + trueBranch=expression COLON falseBranch=conditionalExpression # TernaryExpr + ; conditionalOrExpression - : conditionalAndExpression # COFallthrough - | left=conditionalOrExpression OR_SC right=conditionalAndExpression # ConditionalOrExpr - ; + : conditionalAndExpression # COFallthrough + | left=conditionalOrExpression OR_SC right=conditionalAndExpression # ConditionalOrExpr + ; conditionalAndExpression - : equalityExpression # CAFallthrough - | left=conditionalAndExpression AND_SC right=equalityExpression # ConditionalAndExpr - ; + : equalityExpression # CAFallthrough + | left=conditionalAndExpression AND_SC right=equalityExpression # ConditionalAndExpr + ; equalityExpression - : relationalExpression # EqFallthrough - | left=equalityExpression - op= - ( EQUAL - | NOT_EQUAL - | NEAR - ) right=relationalExpression # EqualityExpr - ; + : relationalExpression # EqFallthrough + | left=equalityExpression + op= + ( EQUAL + | NOT_EQUAL + | NEAR + ) right=relationalExpression # EqualityExpr + ; relationalExpression - : shiftExpression # ReFallthrough - | left=relationalExpression - op= - ( LESS_THAN - | GREATER_THAN - | LESS_THAN_OR_EQUAL - | GREATER_THAN_OR_EQUAL - ) right=shiftExpression # RelationalExpr - ; + : shiftExpression # ReFallthrough + | left=relationalExpression + op= + ( LESS_THAN + | GREATER_THAN + | LESS_THAN_OR_EQUAL + | GREATER_THAN_OR_EQUAL + ) right=shiftExpression # RelationalExpr + ; shiftExpression - : additiveExpression # ShFallthrough - | left=shiftExpression op=( LEFT_SHIFT | RIGHT_SHIFT ) right=additiveExpression # ShiftExpr - ; + : additiveExpression # ShFallthrough + | left=shiftExpression op=( LEFT_SHIFT | RIGHT_SHIFT ) right=additiveExpression # ShiftExpr + ; additiveExpression - : multiplicativeExpression # AdFallthrough - | left=additiveExpression op=( PLUS | MINUS ) right=multiplicativeExpression # AddExpr - ; + : multiplicativeExpression # AdFallthrough + | left=additiveExpression op=( PLUS | MINUS ) right=multiplicativeExpression # AddExpr + ; multiplicativeExpression - : powerExpression # MuFallthrough - | left=multiplicativeExpression - op= - ( TIMES - | DIVIDE - | MODULO - ) right=powerExpression # MultiplicativeExpr - ; + : powerExpression # MuFallthrough + | left=multiplicativeExpression + op= + ( TIMES + | DIVIDE + | MODULO + ) right=powerExpression # MultiplicativeExpr + ; powerExpression - : unaryExpression # PwFallthrough - | left=powerExpression POWER right=unaryExpression # PowerExpr - ; + : unaryExpression # PwFallthrough + | left=powerExpression POWER right=unaryExpression # PowerExpr + ; unaryExpression - : op=( INCREMENT | DECREMENT ) target=ID # PreCrementExpr - | op=( PLUS | MINUS ) expr=unaryExpression # PlusMinusExpr - | postfixExpression # UaFallthrough - | COMPLEMENT expr=unaryExpression # ComplementExpr - | EXCLAMATION_MARK expr=unaryExpression # NotExpr - ; + : op=( INCREMENT | DECREMENT ) target=ID # PreCrementExpr + | op=( PLUS | MINUS ) expr=unaryExpression # PlusMinusExpr + | postfixExpression # UaFallthrough + | COMPLEMENT expr=unaryExpression # ComplementExpr + | EXCLAMATION_MARK expr=unaryExpression # NotExpr + ; postfixExpression - : unprioritizedExpression # PoFallthrough - | target=ID op=( INCREMENT | DECREMENT) # PostCrementExpr - | expr=postfixExpression op=EXCLAMATION_MARK # PostfixExpr - ; + : unprioritizedExpression # PoFallthrough + | target=ID op=( INCREMENT | DECREMENT) # PostCrementExpr + | expr=postfixExpression op=EXCLAMATION_MARK # PostfixExpr + ; unprioritizedExpression : functionCall # FunctionCallExpr From 777b132a041cbba7c7fe971c0e3150f523a9844a Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 27 Oct 2019 12:58:32 -0700 Subject: [PATCH 358/366] Catch small edge-case in parser --- .../src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 | 2 +- .../sk89q/worldedit/internal/expression/ExpressionTest.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 index 107aa5176..507aa3ad0 100644 --- a/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 +++ b/worldedit-core/src/main/antlr/com/sk89q/worldedit/antlr/Expression.g4 @@ -63,7 +63,7 @@ fragment EXP_CHAR : [eE] ; fragment DECIMAL : '.' DIGIT+ ( EXP_CHAR SIGN? DIGIT+ )? ; // All numbers are treated the same. No int/dec divide. -NUMBER : SIGN? ( DIGIT+ DECIMAL? | DECIMAL ) ; +NUMBER : ( DIGIT+ DECIMAL? | DECIMAL ) ; ID : [A-Za-z] [0-9A-Za-z_]* ; diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java index c33112f05..a8a30ba40 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java @@ -74,6 +74,11 @@ public class ExpressionTest { assertEquals(8, compile("foo+bar", "foo", "bar").evaluate(5D, 3D), 0); } + @Test + void testTightTokenization() { + assertEquals(4, simpleEval("3+1"), 0); + } + @Test public void testErrors() { // test lexer errors From 257988b14915ee05f6e331cd61e035cf5e6c656d Mon Sep 17 00:00:00 2001 From: Kenzie Togami Date: Sun, 27 Oct 2019 15:15:44 -0700 Subject: [PATCH 359/366] Add tests for expressions listed on the docs --- .../expression/BaseExpressionTest.java | 100 ++++++++++ .../internal/expression/ExpressionTest.java | 69 +------ .../expression/RealExpressionTest.java | 171 ++++++++++++++++++ 3 files changed, 272 insertions(+), 68 deletions(-) create mode 100644 worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java create mode 100644 worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/RealExpressionTest.java diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java new file mode 100644 index 000000000..2cce5ca41 --- /dev/null +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/BaseExpressionTest.java @@ -0,0 +1,100 @@ +/* + * 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.internal.expression; + +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Platform; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Common setup code for expression tests. + */ +class BaseExpressionTest { + + static double readSlot(Expression expr, String name) { + return expr.getSlots().getSlotValue(name).orElseThrow(IllegalStateException::new); + } + + private Platform mockPlat = mock(Platform.class); + + @BeforeEach + void setup() { + when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() { + @Override + public void load() { + } + }); + WorldEdit.getInstance().getPlatformManager().register(mockPlat); + } + + @AfterEach + void tearDown() { + WorldEdit.getInstance().getPlatformManager().unregister(mockPlat); + } + + double simpleEval(String expressionString) throws ExpressionException { + final Expression expression = compile(expressionString); + + expression.setEnvironment(new ExpressionEnvironment() { + @Override + public int getBlockType(double x, double y, double z) { + return (int) x; + } + + @Override + public int getBlockData(double x, double y, double z) { + return (int) y; + } + + @Override + public int getBlockTypeAbs(double x, double y, double z) { + return (int) x*10; + } + + @Override + public int getBlockDataAbs(double x, double y, double z) { + return (int) y*10; + } + + @Override + public int getBlockTypeRel(double x, double y, double z) { + return (int) x*100; + } + + @Override + public int getBlockDataRel(double x, double y, double z) { + return (int) y*100; + } + }); + + return expression.evaluate(); + } + + Expression compile(String expressionString, String... variableNames) throws ExpressionException { + final Expression expression = Expression.compile(expressionString, variableNames); + expression.optimize(); + return expression; + } +} diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java index a8a30ba40..5520c660e 100644 --- a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/ExpressionTest.java @@ -19,11 +19,6 @@ package com.sk89q.worldedit.internal.expression; -import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.extension.platform.Platform; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.time.Duration; @@ -34,27 +29,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -public class ExpressionTest { - - private Platform mockPlat = mock(Platform.class); - - @BeforeEach - public void setup() { - when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() { - @Override - public void load() { - } - }); - WorldEdit.getInstance().getPlatformManager().register(mockPlat); - } - - @AfterEach - public void tearDown() { - WorldEdit.getInstance().getPlatformManager().unregister(mockPlat); - } +class ExpressionTest extends BaseExpressionTest { @Test public void testEvaluate() throws ExpressionException { @@ -192,47 +168,4 @@ public class ExpressionTest { assertTrue(e.getMessage().contains("Calculations exceeded time limit")); } - private double simpleEval(String expressionString) throws ExpressionException { - final Expression expression = compile(expressionString); - - expression.setEnvironment(new ExpressionEnvironment() { - @Override - public int getBlockType(double x, double y, double z) { - return (int) x; - } - - @Override - public int getBlockData(double x, double y, double z) { - return (int) y; - } - - @Override - public int getBlockTypeAbs(double x, double y, double z) { - return (int) x*10; - } - - @Override - public int getBlockDataAbs(double x, double y, double z) { - return (int) y*10; - } - - @Override - public int getBlockTypeRel(double x, double y, double z) { - return (int) x*100; - } - - @Override - public int getBlockDataRel(double x, double y, double z) { - return (int) y*100; - } - }); - - return expression.evaluate(); - } - - private Expression compile(String expressionString, String... variableNames) throws ExpressionException { - final Expression expression = Expression.compile(expressionString, variableNames); - expression.optimize(); - return expression; - } } diff --git a/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/RealExpressionTest.java b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/RealExpressionTest.java new file mode 100644 index 000000000..625e023a1 --- /dev/null +++ b/worldedit-core/src/test/java/com/sk89q/worldedit/internal/expression/RealExpressionTest.java @@ -0,0 +1,171 @@ +/* + * 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.internal.expression; + +import com.sk89q.worldedit.math.Vector3; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Test class for various real-world expressions. + */ +class RealExpressionTest extends BaseExpressionTest { + + private static final class TestCase { + + final Vector3 loc; + final double result; + final Consumer postChecks; + + private TestCase(Vector3 loc, double result, Consumer postChecks) { + this.loc = loc; + this.result = result; + this.postChecks = postChecks; + } + + TestCase withData(int expectedData) { + return new TestCase(loc, result, expr -> { + postChecks.accept(expr); + double data = readSlot(expr, "data"); + assertEquals(expectedData, (int) data, + "Test case " + this + " failed (data)"); + }); + } + + @Override + public String toString() { + return loc + " -> " + result; + } + } + + private static TestCase testCase(Vector3 loc, double result) { + return testCase(loc, result, e -> { + }); + } + + private static TestCase testCase(Vector3 loc, double result, Consumer postChecks) { + return new TestCase(loc, result, postChecks); + } + + private void checkExpression(String expr, TestCase... cases) { + Expression compiled = compile(expr, "x", "y", "z"); + for (TestCase aCase : cases) { + Vector3 loc = aCase.loc; + assertEquals(aCase.result, compiled.evaluate(loc.getX(), loc.getY(), loc.getZ()), 0, + "Test case " + aCase + " failed (result)"); + aCase.postChecks.accept(compiled); + } + } + + @Test + void torus() { + checkExpression("(0.75-sqrt(x^2+y^2))^2+z^2 < 0.25^2", + testCase(Vector3.at(0, 0, 0), 0), + testCase(Vector3.at(0.5, 0.5, 0.5), 0), + testCase(Vector3.at(1, 0, 0), 0), + testCase(Vector3.at(0.5, 0.5, 0), 1), + testCase(Vector3.at(0.75, 0.5, 0), 1), + testCase(Vector3.at(0.75, 0, 0), 1)); + } + + @Test + void gnarledOakTree() { + checkExpression("(0.5+sin(atan2(x,z)*8)*0.2)*(sqrt(x*x+z*z)/0.5)^(-2)-1.2 < y", + testCase(Vector3.at(-1, -1, -1), 1), + testCase(Vector3.at(-1, 0, 1), 1), + testCase(Vector3.at(1, 1, 1), 1), + testCase(Vector3.at(0, 0, -1), 1), + testCase(Vector3.at(0, 0, 0), 0), + testCase(Vector3.at(0, 1, 0), 0), + testCase(Vector3.at(0, 0, 0.32274), 0), + testCase(Vector3.at(0, 0, 0.32275), 1)); + } + + @Test + void rainbowTorus() { + checkExpression("data=(32+15/2/pi*atan2(x,y))%16; (0.75-sqrt(x^2+y^2))^2+z^2 < 0.25^2", + testCase(Vector3.at(0, 0, 0), 0), + testCase(Vector3.at(0.5, 0.5, 0.5), 0), + testCase(Vector3.at(1, 0, 0), 0), + testCase(Vector3.at(0.5, 0.5, 0), 1).withData(1), + testCase(Vector3.at(0.75, 0.5, 0), 1).withData(2), + testCase(Vector3.at(0.75, 0, 0), 1).withData(3)); + } + + @Test + void rainbowEgg() { + TestCase[] testCases = new TestCase[15]; + for (int i = 0; i < testCases.length; i++) { + testCases[i] = testCase(Vector3.at(0, i / 16.0 - 0.5, 0), 1) + .withData((i + 9) % 16); + } + testCases = Stream.concat(Stream.of(testCases), Stream.of( + testCase(Vector3.at(0, 1, 0), 0) + )).toArray(TestCase[]::new); + checkExpression("data=(32+y*16+1)%16; y^2/9+x^2/6*(1/(1-0.4*y))+z^2/6*(1/(1-0.4*y))<0.08", + testCases); + } + + @Test + void heart() { + checkExpression("(z/2)^2+x^2+(5*y/4-sqrt(abs(x)))^2<0.6", + testCase(Vector3.at(0, 0, -1), 1), + testCase(Vector3.at(0, 1, -1), 0), + testCase(Vector3.at(-0.5, 1, 0), 1)); + } + + @Test + void sineWave() { + checkExpression("sin(x*5)/2-0.03", + testCase(Vector3.at(0, 0, 0), 1), + testCase(Vector3.at(0, 1, 0), 1), + testCase(Vector3.at(0, 1, 1), 1), + testCase(Vector3.at(1, 1, 1), 1), + testCase(Vector3.at(0, 0, 1), 0), + testCase(Vector3.at(1, 0, 1), 0)); + } +} From bf3b91aaa791c93269cd03e410f9937938343b6c Mon Sep 17 00:00:00 2001 From: Pieter12345 Date: Mon, 28 Oct 2019 15:02:24 +0100 Subject: [PATCH 360/366] Fix stack command diagonal shifting with -s flag Fix `//stack -s [num]` shifting the selection to unexpected places. This fix causes `//stack -s [num]` behavior in diagonal directions to be consistent with the behavior in non-diagonal directions, which means that the last stack will be selected. --- .../main/java/com/sk89q/worldedit/command/RegionCommands.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 65c1c2f50..2aa18962f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -373,9 +373,9 @@ public class RegionCommands { if (moveSelection) { try { - final BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()); + final BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1); - final BlockVector3 shiftVector = direction.toVector3().multiply(count * (Math.abs(direction.dot(size)) + 1)).toBlockPoint(); + final BlockVector3 shiftVector = direction.multiply(size).multiply(count); region.shift(shiftVector); session.getRegionSelector(world).learnChanges(); From 575463a8e9d9a6b93338ed0fdf0d30272f53ee59 Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 9 Nov 2019 11:31:51 -0500 Subject: [PATCH 361/366] Make a few more selection commands usable from console. --- .../worldedit/command/SelectionCommands.java | 62 +++++++++++-------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index 431785923..5cf8dc676 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -80,6 +80,7 @@ import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.Switch; +import org.enginehub.piston.exception.StopExecutionException; import java.util.List; import java.util.Optional; @@ -206,7 +207,7 @@ public class SelectionCommands { ) @Logging(POSITION) @CommandPermissions("worldedit.selection.chunk") - public void chunk(Player player, LocalSession session, + public void chunk(Actor actor, World world, LocalSession session, @Arg(desc = "The chunk to select", def = "") BlockVector2 coordinates, @Switch(name = 's', desc = "Expand your selection to encompass all chunks that are part of it") @@ -215,7 +216,6 @@ public class SelectionCommands { boolean useChunkCoordinates) throws WorldEditException { final BlockVector3 min; final BlockVector3 max; - final World world = player.getWorld(); if (expandSelection) { Region region = session.getSelection(world); @@ -225,7 +225,7 @@ public class SelectionCommands { min = BlockVector3.at(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); max = BlockVector3.at(max2D.getBlockX() * 16 + 15, world.getMaxY(), max2D.getBlockZ() * 16 + 15); - player.print("Chunks selected: (" + actor.print("Chunks selected: (" + min2D.getBlockX() + ", " + min2D.getBlockZ() + ") - (" + max2D.getBlockX() + ", " + max2D.getBlockZ() + ")"); } else { @@ -237,13 +237,17 @@ public class SelectionCommands { : ChunkStore.toChunk(coordinates.toBlockVector3()); } else { // use player loc - min2D = ChunkStore.toChunk(player.getBlockLocation().toVector().toBlockPoint()); + if (actor instanceof Locatable) { + min2D = ChunkStore.toChunk(((Locatable) actor).getBlockLocation().toVector().toBlockPoint()); + } else { + throw new StopExecutionException(TextComponent.of("A player or coordinates are required.")); + } } min = BlockVector3.at(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); max = min.add(15, world.getMaxY(), 15); - player.print("Chunk selected: " + actor.print("Chunk selected: " + min2D.getBlockX() + ", " + min2D.getBlockZ()); } @@ -253,11 +257,11 @@ public class SelectionCommands { } else { selector = new CuboidRegionSelector(world); } - selector.selectPrimary(min, ActorSelectorLimits.forActor(player)); - selector.selectSecondary(max, ActorSelectorLimits.forActor(player)); + selector.selectPrimary(min, ActorSelectorLimits.forActor(actor)); + selector.selectSecondary(max, ActorSelectorLimits.forActor(actor)); session.setRegionSelector(world, selector); - session.dispatchCUISelection(player); + session.dispatchCUISelection(actor); } @@ -433,7 +437,7 @@ public class SelectionCommands { desc = "Get information about the selection" ) @CommandPermissions("worldedit.selection.size") - public void size(Player player, LocalSession session, + public void size(Actor actor, World world, LocalSession session, @Switch(name = 'c', desc = "Get clipboard info instead") boolean clipboardInfo) throws WorldEditException { Region region; @@ -443,23 +447,23 @@ public class SelectionCommands { region = clipboard.getRegion(); BlockVector3 origin = clipboard.getOrigin(); - player.print("Offset: " + origin); + actor.print("Offset: " + origin); } else { - region = session.getSelection(player.getWorld()); + region = session.getSelection(world); - player.print("Type: " + session.getRegionSelector(player.getWorld()).getTypeName()); + actor.print("Type: " + session.getRegionSelector(world).getTypeName()); - for (String line : session.getRegionSelector(player.getWorld()).getInformationLines()) { - player.print(line); + for (String line : session.getRegionSelector(world).getInformationLines()) { + actor.print(line); } } BlockVector3 size = region.getMaximumPoint() .subtract(region.getMinimumPoint()) .add(1, 1, 1); - player.print("Size: " + size); - player.print("Cuboid distance: " + region.getMaximumPoint().distance(region.getMinimumPoint())); - player.print("# of blocks: " + region.getArea()); + actor.print("Size: " + size); + actor.print("Cuboid distance: " + region.getMaximumPoint().distance(region.getMinimumPoint())); + actor.print("# of blocks: " + region.getArea()); } @@ -468,11 +472,11 @@ public class SelectionCommands { desc = "Counts the number of blocks matching a mask" ) @CommandPermissions("worldedit.analysis.count") - public void count(Player player, LocalSession session, EditSession editSession, + public void count(Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "The mask of blocks to match") Mask mask) throws WorldEditException { - int count = editSession.countBlocks(session.getSelection(player.getWorld()), mask); - player.print("Counted: " + count); + int count = editSession.countBlocks(session.getSelection(world), mask); + actor.print("Counted: " + count); } @Command( @@ -480,7 +484,7 @@ public class SelectionCommands { desc = "Get the distribution of blocks in the selection" ) @CommandPermissions("worldedit.analysis.distr") - public void distr(Player player, LocalSession session, + public void distr(Actor actor, World world, LocalSession session, @Switch(name = 'c', desc = "Get the distribution of the clipboard instead") boolean clipboardDistr, @Switch(name = 'd', desc = "Separate blocks by state") @@ -497,8 +501,8 @@ public class SelectionCommands { Operations.completeBlindly(visitor); distribution = count.getDistribution(); } else { - try (EditSession editSession = session.createEditSession(player)) { - distribution = editSession.getBlockDistribution(session.getSelection(player.getWorld()), separateStates); + try (EditSession editSession = session.createEditSession(actor)) { + distribution = editSession.getBlockDistribution(session.getSelection(world), separateStates); } } session.setLastDistribution(distribution); @@ -506,19 +510,23 @@ public class SelectionCommands { } else { distribution = session.getLastDistribution(); if (distribution == null) { - player.printError("No previous distribution."); + actor.printError("No previous distribution."); return; } } if (distribution.isEmpty()) { // *Should* always be false - player.printError("No blocks counted."); + actor.printError("No blocks counted."); return; } final int finalPage = page; - WorldEditAsyncCommandBuilder.createAndSendMessage(player, - () -> new BlockDistributionResult(distribution, separateStates).create(finalPage), null); + WorldEditAsyncCommandBuilder.createAndSendMessage(actor, + () -> { + BlockDistributionResult res = new BlockDistributionResult(distribution, separateStates); + if (!actor.isPlayer()) res.formatForConsole(); + return res.create(finalPage); + }, null); } @Command( From e5fe051340dcc6d3f68fca54fc35ab77ba26090e Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 9 Nov 2019 11:32:24 -0500 Subject: [PATCH 362/366] Use persistent leaves for garden patch generator (/pumpkins) --- .../function/generator/GardenPatchGenerator.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java index 5d1aa01c5..19f5ed855 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/GardenPatchGenerator.java @@ -26,7 +26,6 @@ import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypes; import java.util.Random; @@ -39,6 +38,7 @@ public class GardenPatchGenerator implements RegionFunction { private final Random random = new Random(); private final EditSession editSession; private Pattern plant = getPumpkinPattern(); + private Pattern leafPattern = BlockTypes.OAK_LEAVES.getDefaultState().with(BlockTypes.OAK_LEAVES.getProperty("persistent"), true); private int affected; /** @@ -96,7 +96,7 @@ public class GardenPatchGenerator implements RegionFunction { } } - setBlockIfAir(editSession, pos, BlockTypes.OAK_LEAVES.getDefaultState()); + setBlockIfAir(editSession, pos, leafPattern); affected++; int t = random.nextInt(4); @@ -166,10 +166,9 @@ public class GardenPatchGenerator implements RegionFunction { return false; } - BlockState leavesBlock = BlockTypes.OAK_LEAVES.getDefaultState(); if (editSession.getBlock(position).getBlockType().getMaterial().isAir()) { - editSession.setBlock(position, leavesBlock); + editSession.setBlock(position, leafPattern); } placeVine(position, position.add(0, 0, 1)); @@ -193,12 +192,12 @@ public class GardenPatchGenerator implements RegionFunction { * Set a block only if there's no block already there. * * @param position the position - * @param block the block to set + * @param pattern the pattern to set * @return if block was changed * @throws MaxChangedBlocksException thrown if too many blocks are changed */ - private static > boolean setBlockIfAir(EditSession session, BlockVector3 position, B block) throws MaxChangedBlocksException { - return session.getBlock(position).getBlockType().getMaterial().isAir() && session.setBlock(position, block); + private static boolean setBlockIfAir(EditSession session, BlockVector3 position, Pattern pattern) throws MaxChangedBlocksException { + return session.getBlock(position).getBlockType().getMaterial().isAir() && session.setBlock(position, pattern); } /** From 2b1a7ed9433b3b3a9e45bc8b82ca56159e3c131b Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 9 Nov 2019 11:33:55 -0500 Subject: [PATCH 363/366] Make lrbuild tool use history. --- .../command/tool/LongRangeBuildTool.java | 68 ++++++++++++------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java index 66366f0e3..f82d6961f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/tool/LongRangeBuildTool.java @@ -26,6 +26,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; @@ -55,41 +56,56 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { Location pos = getTargetFace(player); if (pos == null) return false; - try (EditSession eS = session.createEditSession(player)) { - eS.disableBuffering(); - BlockVector3 blockPoint = pos.toVector().toBlockPoint(); - BaseBlock applied = secondary.apply(blockPoint); - if (applied.getBlockType().getMaterial().isAir()) { - eS.setBlock(blockPoint, secondary); - } else { - eS.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), secondary); - } - return true; - } catch (MaxChangedBlocksException ignored) { - // one block? eat it - } - return false; + BlockBag bag = session.getBlockBag(player); + try (EditSession editSession = session.createEditSession(player)) { + try { + editSession.disableBuffering(); + BlockVector3 blockPoint = pos.toVector().toBlockPoint(); + BaseBlock applied = secondary.apply(blockPoint); + if (applied.getBlockType().getMaterial().isAir()) { + editSession.setBlock(blockPoint, secondary); + } else { + editSession.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), secondary); + } + } catch (MaxChangedBlocksException ignored) { + } finally { + session.remember(editSession); + } + } finally { + if (bag != null) { + bag.flushChanges(); + } + } + return true; } @Override public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { Location pos = getTargetFace(player); if (pos == null) return false; - try (EditSession eS = session.createEditSession(player)) { - eS.disableBuffering(); - BlockVector3 blockPoint = pos.toVector().toBlockPoint(); - BaseBlock applied = primary.apply(blockPoint); - if (applied.getBlockType().getMaterial().isAir()) { - eS.setBlock(blockPoint, primary); - } else { - eS.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), primary); + BlockBag bag = session.getBlockBag(player); + + try (EditSession editSession = session.createEditSession(player)) { + try { + editSession.disableBuffering(); + BlockVector3 blockPoint = pos.toVector().toBlockPoint(); + BaseBlock applied = primary.apply(blockPoint); + if (applied.getBlockType().getMaterial().isAir()) { + editSession.setBlock(blockPoint, primary); + } else { + editSession.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), primary); + } + } catch (MaxChangedBlocksException ignored) { + } finally { + session.remember(editSession); + } + } finally { + if (bag != null) { + bag.flushChanges(); } - return true; - } catch (MaxChangedBlocksException ignored) { - // one block? eat it } - return false; + return true; } private Location getTargetFace(Player player) { From fc5c625f021232c883c00a52806e5812cbc69a5a Mon Sep 17 00:00:00 2001 From: wizjany Date: Sat, 9 Nov 2019 11:41:18 -0500 Subject: [PATCH 364/366] Add -n flag to //paste to select without pasting. --- .../worldedit/command/ClipboardCommands.java | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) 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 1b583aef5..b90fe7786 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 @@ -140,6 +140,8 @@ public class ClipboardCommands { boolean atOrigin, @Switch(name = 's', desc = "Select the region after pasting") boolean selectPasted, + @Switch(name = 'n', desc = "No paste, select only. (Implies -s)") + boolean onlySelect, @Switch(name = 'e', desc = "Paste entities if available") boolean pasteEntities, @Switch(name = 'b', desc = "Paste biomes if available") @@ -151,19 +153,23 @@ public class ClipboardCommands { ClipboardHolder holder = session.getClipboard(); Clipboard clipboard = holder.getClipboard(); Region region = clipboard.getRegion(); + List messages = Lists.newArrayList(); BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(actor); - Operation operation = holder - .createPaste(editSession) - .to(to) - .ignoreAirBlocks(ignoreAirBlocks) - .copyBiomes(pasteBiomes) - .copyEntities(pasteEntities) - .maskSource(sourceMask) - .build(); - Operations.completeLegacy(operation); + if (!onlySelect) { + Operation operation = holder + .createPaste(editSession) + .to(to) + .ignoreAirBlocks(ignoreAirBlocks) + .copyBiomes(pasteBiomes) + .copyEntities(pasteEntities) + .maskSource(sourceMask) + .build(); + Operations.completeLegacy(operation); + operation.addStatusMessages(messages); + } - if (selectPasted) { + if (selectPasted || onlySelect) { BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin()); Vector3 realTo = to.toVector3().add(holder.getTransform().apply(clipboardOffset.toVector3())); Vector3 max = realTo.add(holder.getTransform().apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3())); @@ -173,9 +179,11 @@ public class ClipboardCommands { selector.explainRegionAdjust(actor, session); } - actor.print("The clipboard has been pasted at " + to); - List messages = Lists.newArrayList(); - operation.addStatusMessages(messages); + if (onlySelect) { + actor.print("Selected clipboard paste region."); + } else { + actor.print("The clipboard has been pasted at " + to); + } messages.forEach(actor::print); } From 89bc664f69da9fcfe9b225d805d5684f2dfab37f Mon Sep 17 00:00:00 2001 From: Brokkonaut Date: Tue, 12 Nov 2019 12:09:28 +0100 Subject: [PATCH 365/366] Fix flipping of chests and stairs (#526) * Fix flipping of chests and stairs * Check if the new property value is valid before updating * Only for horizontal flips double chests/stairs should be modified --- .../transform/BlockTransformExtent.java | 33 +++++++++++++++++++ .../math/transform/AffineTransform.java | 8 +++++ 2 files changed, 41 insertions(+) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java index fe577e709..46081ab94 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.registry.state.BooleanProperty; import com.sk89q.worldedit.registry.state.DirectionalProperty; @@ -162,6 +163,38 @@ public class BlockTransformExtent extends AbstractDelegateExtent { } } } + } else if (property.getName().equals("type") && transform instanceof AffineTransform) { + // chests + if (((AffineTransform) transform).isHorizontalFlip()) { + String value = (String) block.getState(property); + String newValue = null; + if ("left".equals(value)) { + newValue = "right"; + } else if ("right".equals(value)) { + newValue = "left"; + } + if (newValue != null && enumProp.getValues().contains(newValue)) { + result = result.with(enumProp, newValue); + } + } + } else if (property.getName().equals("shape") && transform instanceof AffineTransform) { + // stairs + if (((AffineTransform) transform).isHorizontalFlip()) { + String value = (String) block.getState(property); + String newValue = null; + if ("outer_left".equals(value)) { + newValue = "outer_right"; + } else if ("outer_right".equals(value)) { + newValue = "outer_left"; + } else if ("inner_left".equals(value)) { + newValue = "inner_right"; + } else if ("inner_right".equals(value)) { + newValue = "inner_left"; + } + if (newValue != null && enumProp.getValues().contains(newValue)) { + result = result.with(enumProp, newValue); + } + } } } else if (property instanceof IntegerProperty) { IntegerProperty intProp = (IntegerProperty) property; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java index f3e9a3876..6cb976440 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java @@ -312,6 +312,14 @@ public class AffineTransform implements Transform { } } + /** + * Returns if this affine transform is representing a horizontal flip. + */ + public boolean isHorizontalFlip() { + // use the determinant of the x-z submatrix to check if this is a horizontal flip + return m00 * m22 - m02 * m20 < 0; + } + @Override public String toString() { return String.format("Affine[%g %g %g %g, %g %g %g %g, %g %g %g %g]}", m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23); From 77ef0ae41778b43a6841d715acc39dda51541213 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Fri, 15 Nov 2019 12:02:46 +1000 Subject: [PATCH 366/366] Bypass Bukkit in more situations (#532) * Bypass Bukkit in more situations * Use orElseGet * Apply the same optimisation in the reverse BlockData adapter, and use lambdas instead of AIC * Remove bukkit type checks * Improve reliability of fallbacks --- .../sk89q/worldedit/bukkit/BukkitAdapter.java | 58 ++++++++++-------- .../bukkit/adapter/BukkitImplAdapter.java | 4 ++ .../src/main/resources/worldedit-adapters.jar | Bin 433302 -> 477811 bytes 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java index 79526882f..ab5fabd18 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitAdapter.java @@ -21,7 +21,6 @@ package com.sk89q.worldedit.bukkit; import static com.google.common.base.Preconditions.checkNotNull; -import com.google.common.base.Function; import com.sk89q.worldedit.NotABlockException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; @@ -29,6 +28,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.util.Location; @@ -45,6 +45,8 @@ import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemTypes; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Biome; @@ -52,6 +54,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.EnumMap; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -349,18 +352,19 @@ public class BukkitAdapter { return org.bukkit.entity.EntityType.fromName(entityType.getId().substring(10)); } + private static EnumMap materialBlockTypeCache = new EnumMap<>(Material.class); + private static EnumMap materialItemTypeCache = new EnumMap<>(Material.class); + /** * Converts a Material to a BlockType * * @param material The material * @return The blocktype */ + @Nullable public static BlockType asBlockType(Material material) { checkNotNull(material); - if (!material.isBlock()) { - throw new IllegalArgumentException(material.getKey().toString() + " is not a block!"); - } - return BlockTypes.get(material.getKey().toString()); + return materialBlockTypeCache.computeIfAbsent(material, input -> BlockTypes.get(material.getKey().toString())); } /** @@ -369,15 +373,14 @@ public class BukkitAdapter { * @param material The material * @return The itemtype */ + @Nullable public static ItemType asItemType(Material material) { checkNotNull(material); - if (!material.isItem()) { - throw new IllegalArgumentException(material.getKey().toString() + " is not an item!"); - } - return ItemTypes.get(material.getKey().toString()); + return materialItemTypeCache.computeIfAbsent(material, input -> ItemTypes.get(material.getKey().toString())); } - private static Map blockStateCache = new HashMap<>(); + private static Int2ObjectMap blockStateCache = new Int2ObjectOpenHashMap<>(); + private static Map blockStateStringCache = new HashMap<>(); /** * Create a WorldEdit BlockState from a Bukkit BlockData @@ -387,21 +390,32 @@ public class BukkitAdapter { */ public static BlockState adapt(BlockData blockData) { checkNotNull(blockData); - return blockStateCache.computeIfAbsent(blockData.getAsString(), new Function() { - @Nullable - @Override - public BlockState apply(@Nullable String input) { + + if (WorldEditPlugin.getInstance().getBukkitImplAdapter() == null) { + return blockStateStringCache.computeIfAbsent(blockData.getAsString(), input -> { try { return WorldEdit.getInstance().getBlockFactory().parseFromInput(input, TO_BLOCK_CONTEXT).toImmutableState(); } catch (InputParseException e) { e.printStackTrace(); return null; } - } - }); + }); + } else { + return blockStateCache.computeIfAbsent( + WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(blockData).orElseGet( + () -> blockData.getAsString().hashCode() + ), input -> { + try { + return WorldEdit.getInstance().getBlockFactory().parseFromInput(blockData.getAsString(), TO_BLOCK_CONTEXT).toImmutableState(); + } catch (InputParseException e) { + e.printStackTrace(); + return null; + } + }); + } } - private static Map blockDataCache = new HashMap<>(); + private static Int2ObjectMap blockDataCache = new Int2ObjectOpenHashMap<>(); /** * Create a Bukkit BlockData from a WorldEdit BlockStateHolder @@ -411,13 +425,9 @@ public class BukkitAdapter { */ public static > BlockData adapt(B block) { checkNotNull(block); - return blockDataCache.computeIfAbsent(block.getAsString(), new Function() { - @Nullable - @Override - public BlockData apply(@Nullable String input) { - return Bukkit.createBlockData(block.getAsString()); - } - }).clone(); + // Should never not have an ID for this BlockState. + int cacheKey = BlockStateIdAccess.getBlockStateId(block.toImmutableState()).orElseGet(block::hashCode); + return blockDataCache.computeIfAbsent(cacheKey, input -> Bukkit.createBlockData(block.getAsString())).clone(); } /** 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 4bb915c56..be5197e8c 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 @@ -33,6 +33,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -175,6 +176,9 @@ public interface BukkitImplAdapter { */ BaseItemStack adapt(ItemStack itemStack); + default OptionalInt getInternalBlockStateId(BlockData data) { + return OptionalInt.empty(); + } /** * Retrieve the internal ID for a given state, if possible. diff --git a/worldedit-bukkit/src/main/resources/worldedit-adapters.jar b/worldedit-bukkit/src/main/resources/worldedit-adapters.jar index 92171a9cc11fdbcb3d850afdd712ae88eca7ab13..43a6d50099453f4e3d8b5f2a8c082c9a503d0010 100644 GIT binary patch delta 85439 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